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[L−1]。
输入输出格式
输入的第一行包含三个用空格分隔的正整数 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 ∣x−i∣<=r and ∣y−j∣<=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,i−r),b=max(1,j−r),c=min(n,i+r),d=min(n,j+r)
那么这个矩形内元素个数为 ( c − a + 1 ) ∗ ( d − b + 1 ) (c - a + 1) * (d - b + 1) (c−a+1)∗(d−b+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 赛题练习