CCF CSP-2021-04 赛题练习

Posted ZSYL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CCF CSP-2021-04 赛题练习相关的知识,希望对你有一定的参考价值。

这里写目录标题

前言

西电上机喜欢CCF真题,于是加以练习。题目题解来源Github开源项目 日沉云起

仅供学习交流!

【CCF CSP-202104-1】灰度直方图

题意概述

一副 n × m n\\times m n×m的灰度图像的灰度直方图可以表示为一个长度为 L L L的数组 h h h,其中 h [ x ] ( 0 < = x < L ) h[x] (0<=x<L) h[x](0<=x<L)表示该图像中灰度值为 x x x的像素个数。已知一副图像的灰度矩阵 A A A,试计算其灰度直方图 h [ 0 ] , h [ 1 ] , ⋯   , h [ L − 1 ] h[0],h[1],\\cdots,h[L-1] h[0],h[1],,h[L1]

输入输出格式

输入的第一行包含三个用空格分隔的正整数 n , m , L n, m, L n,m,L,含义如前文所述。接下来 n n n行,每行给出 m m m个整数,表示整个灰度图像。

输出仅一行,包含用空格分隔的 L L L个整数,表示输入图像的灰度直方图。

数据规模

0 < n , m < = 500 , 4 < = L < = 256 0<n,m<=500, 4<=L<=256 0<n,m<=500,4<=L<=256

C++代码

#include <bits/stdc++.h>
using namespace std;
using gg = long long;
int main() 
    ios::sync_with_stdio(false);
    cin.tie(0);
    gg ni, mi, li, xi;
    cin >> ni >> mi >> li;
    vector<gg> ans(li);
    for (gg i = 0; i < ni; ++i) 
        for (gg j = 0; j < mi; ++j) 
            cin >> xi;
            ans[xi]++;  // 对应像素点++
        
    
    for (gg i : ans) 
        cout << i << " ";
    
    return 0;

#include <bits/stdc++.h>

#define maxl 256

int h[maxl];

int main () 
    int n, m, l;
    int readin;
    scanf("%d%d%d", &n, &m, &l);
    for (int i = 0; i < n; i++) 
        for (int j = 0; j  < m; j++) 
            scanf("%d", &readin);
            h[readin]++;
        
    
    for (int i = 0; i < l; i++) 
        printf("%d ", h[i]);
    
    return 0;

【CCF CSP-202104-2】邻域均值

题意概述

给出一个 n × n n\\times n n×n的矩阵 A,对于矩阵中任意一个元素 A i j ( 0 < = i , j < n ) A_ij(0<=i,j<n) Aij(0<=i,j<n),其邻域定义为附近若干元素的集和:
N e i g h b o r ( i , j , r ) = A x y ∣ 0 < = x , y < n   a n d   ∣ x − i ∣ < = r   a n d   ∣ y − j ∣ < = r Neighbor(i,j,r)=\\A_xy|0<=x,y<n\\ and\\ |x-i|<=r\\ and\\ |y-j|<=r\\ Neighbor(i,j,r)=Axy∣0<=x,y<n and xi<=r and yj<=r

这里使用了一个额外的参数 r r r来指明 A i j A_ij Aij附近元素的具体范围。如果元素 A i j A_ij Aij邻域中所有元素的平均值小于或等于一个给定的阈值 t t t,我们就认为该元素对应位置的像素处于较暗区域。现给定邻域参数 r r r和阈值 t t t,试统计输入灰度图像中有多少像素处于较暗区域。

输入输出格式

输入的第一行包含三个用空格分隔的正整数 n , l , r , t n,l,r,t n,l,r,t,含义如前文所述。接下来 n n n行,每行给出 n n n个整数,表示整个矩阵。

输出一个整数,表示输入灰度图像中处于较暗区域的像素总数。

数据规模

0 < n < = 600 , 0 < r < = 100 0<n<=600, 0<r<=100 0<n<=600,0<r<=100

算法设计

为了编码简便,假定矩阵行列坐标都从 1 开始。显然, A i j A_ij Aij的邻域元素共同构成了一个矩形,假设这个矩形的左上角坐标为 ( a , b ) (a,b) (a,b),右下角坐标为 ( c , d ) (c,d) (c,d),那么有

a = m a x ( 1 , i − r ) , b = m a x ( 1 , j − r ) , c = m i n ( n , i + r ) , d = m i n ( n , j + r ) a = max(1, i - r), b = max(1, j - r), c = min(n, i + r), d = min(n, j + r) a=max(1,ir),b=max(1,jr),c=min(n,i+r),d=min(n,j+r)

那么这个矩形内元素个数为 ( c − a + 1 ) ∗ ( d − b + 1 ) (c - a + 1) * (d - b + 1) (ca+1)(db+1),关键在于如何快速求解整个矩形内元素的和?如何暴力求解,时间复杂度会高达 O ( n m r 2 ) O(nmr^2) O(nmr2),只能拿到 70 分,可以通过二维前缀和来进行优化。关于二维前缀和的讲解可以参考前缀和,代码模板可以参考二维前缀和与二维差分。这样可以把时间复杂度优化到 O ( n m ) O(nm) O(nm)

C++代码

#include <bits/stdc++.h>
using namespace std;
using gg = long long;
constexpr gg MAX = 6e2 + 5;
gg ni, li, ri, ti;
gg a[MAX][MAX], preSum[MAX][MAX];
//计算前缀和
void getPrefixSum(gg m, gg n) 
    for (gg i = 1; i <= m; ++i) 
        for (gg j = 1; j <= n; ++j) 
            preSum[i][j] = preSum[i - 1][j] + preSum[i][j - 1] - preSum[i - 1][j - 1] + a[i][j];
        
    

//计算将左上角为(r1,c1),右下角为(r2,c2)的矩阵的和
gg getSum(gg r1, gg c1, gg r2, gg c2) 
    return preSum[r2][c2] - preSum[r1 - 1][c2] - preSum[r2][c1 - 1] + preSum[r1 - 1][c1 - 1];

int main() 
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> ni >> li >> ri >> ti;
    for (gg i = 1; i <= ni; ++i) 
        for (gg j = 1; j <= ni; ++j) 
            cin >> a[i][j];
        
    
    getPrefixSum(ni, ni);
    gg ans = 0;
    for (gg i = 1; i <= ni; ++i) 
        for (gg j = 1; j <= ni; ++j) 
            gg a = max(1ll, i - ri), b = max(1ll, j - ri), c = min(ni, i + ri), d = min(ni, j + ri);  // 计算区域的左下角与右上角
            gg res = getSum(a, b, c, d);
            if (res <= ti * (c - a + 1) * (d - b + 1))   // 判断区域平均值是否小于阈值
                ++ans;
            
        
    
    cout << ans << "\\n";
    return 0;

解法2:

#include <cstdio>

#define max(a, b) ((a) > (b) ? (a) : (b));
#define min(a, b) ((a) < (b) ? (a) : (b));
#define MAXN 600

int A[MAXN + 1][MAXN + 1]; // 从1开始计数
int S[MAXN + 1][MAXN + 1]; // S[i][j]:1~i,1~j围成的面积权值和。加1是为了预留边界,简便计算。
int n, l, r, t;

CCF-CSP 202209 赛题练习

CCF CSP-2022-01 赛题练习

CCF-CSP 201604 赛题训练

CCF-CSP 201709 赛题训练

CCF-CSP 201712 赛题训练

CCF-CSP 202203 赛题训练