CCF CSP第2题总结(持续更新中)

第二题难度每年不一,简单的年份理解清题意、想好每一步干什么、用什么数据结构存储,然后直接翻译就可以了,如果要加难度,基本都是时间复杂度方面,常见的方法有动态规划/差分/前缀和等等

目录

2021-09-2 非零段划分

2021-06-2 领域均值

2020-09-2 风险人群筛查

2020-06-2 稀疏向量

2019-12-02 回收站选址

2019-09-2 小明种苹果(续)

2021-09-2 非零段划分

法一:暴力法 for(p=0;p<=maxp;p++) 对每个p求对应的非零段数量,记录最大值 70分

法二:差分法:以变化的视角来看待,观察p每次-1(或+1)时,非零段个数的变化,可以发现影响非零段数量的本质是“凸”和“凹”的情况

思想:将数组中每个值看成对应高度的“山峰”,题中的p相当于“海平面”,所求就是高于海平面的“岛屿”(由若干连续的山峰组成)个数

分两种情况:

两高夹一矮 则当海平面下降到矮峰下面时,就会连起来,岛屿数-1

两矮夹一高 则当海平面下降到高峰下面时,岛屿数+1

将凸和凹的组数保存到ans[]数组中,ans的索引代码山峰的高度,最后在ans数组叠加的过程中记录最大值即可

#include<bits/stdc++.h>
using namespace std;
int a[500005];
int cnt[10005];

int main(){
	int n;
	cin>>n;
	a[0]=0;for(int i=1;i<=n;i++)cin>>a[i];a[n+1]=0;
	n=unique(a,a+n+2)-a;
	for(int i=1;i<n-1;i++) 
		if(a[i-1]<a[i]&&a[i]>a[i+1])
			cnt[a[i]]++;
		else if(a[i-1]>a[i]&&a[i]<a[i+1])
			cnt[a[i]]--;
	int ans=0,sum=0;
	for(int i=10000;i>0;i--){
		sum+=cnt[i];
		ans=max(ans,sum);
	}
	cout<<ans;
} 


2021-06-2 领域均值

二维前缀和

参考了这篇大佬的博客 ​​​​​​ (206条消息) CSP-2邻域均值_Vanghua的博客-CSDN博客,不过自己习惯用x表示行(i),用y表示列(j),本质其实一样的。

第一个循环中i,j的含义是矩阵的右下角

第二个循环中i,j是矩阵的中心,(xl,yt)是矩阵左上角,(xr,yb)是矩阵右下角

#include <iostream>
using namespace std;
int ar[601][601], sum[601][601];

int main() {
	int n, l, r;
	float t;
	cin >> n >> l >> r >> t;
	for(int i = 1; i <= n; i ++) 
		for(int j = 1; j <= n; j ++) {
			cin >> ar[i][j];
			sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + ar[i][j];
		}
	
	int xl, xr, yt, yb, sumVal, cnt = 0;
	float avgVal;
	for(int i = 1; i <= n; i ++) 
		for(int j = 1; j <= n; j ++) {
			yt = j - r >= 1 ? j - r : 1;
			yb = j + r <= n ? j + r : n;
			xl = i - r >= 1 ? i - r : 1;
			xr = i + r <= n ? i + r : n;
			sumVal = sum[xr][yb] - sum[xl - 1][yb] - sum[xr][yt-1] + sum[xl - 1][yt - 1];
			avgVal = (float)sumVal / ((yb - yt + 1) * (xr - xl + 1));
			if(avgVal <= t)
				cnt ++;
		}
	cout << cnt;
}


2020-09-2 风险人群筛查

没用什么算法

理解清题意,直译,f1记录是否经过,f2记录是否停留,pass表示经过人数,stay表示停留人数,内循环结束后根据f1,f2进行pass++,stay++

#include<bits/stdc++.h>
using namespace std;
const int maxn=10005;
int x[maxn],y[maxn];
	
int main(){
	int n,k,t,xl,yd,xr,yu;
	cin>>n>>k>>t>>xl>>yd>>xr>>yu;
	int stay=0,pass=0;
	for(int j=0;j<n;j++){
		int cnt=0;bool f1=0,f2=0;
		for(int i=0;i<t;i++){
			cin>>x[i]>>y[i];
			if(xl<=x[i]&&xr>=x[i]&&yd<=y[i]&&yu>=y[i])
				{
					cnt++; 
					f1=1;
					if(cnt>=k)f2=1;
				}
			else cnt=0;
			
		}
		if(f1)pass++;
		if(f2)stay++;
	}
	cout<<pass<<endl<<stay;	 
} 


2020-06-2 稀疏向量

遍历其中一个向量的非零项索引,查找另一个向量中对应的地方是否也为非零项(相当于查看x[N]或y[N]中是否也有该索引),若有则相乘并累加

其中优化时间复杂度的地方在于,观察可以发现题目中给出的索引都是从小到大排列的,因此在查找的过程当中,不需要找到尾部,一旦大于索引就可以终止查找,并且不需要每次从头查找,只要在每次查找完用一个全局变量标记当前位置,下次接着往后找就行,因此时间复杂度是线性的

#include<bits/stdc++.h>
using namespace std;
int n,a,b;
const int N=5e5+5;
int x[N],y[N];
long u[N],v[N];
long long ans=0;
int w=0;

int search(int f,int c){
	for(int k=w;k<c;k++){
		if(y[k]==f){
			w=k;
			return k;
		}
		if(y[k]>f){
			w=k;
			return -1;
		}
	}
	return -1;
}

int main(){
	cin>>n>>a>>b;
	for(int i=0;i<a;i++)cin>>x[i]>>u[i];
	for(int j=0;j<b;j++)cin>>y[j]>>v[j];
	if(a<=b){
		for(int i=0;i<a;i++){
			if(search(x[i],a)!=-1)ans+=u[i]*v[search(x[i],a)];
		}
	}
	else{
		for(int i=0;i<b;i++){
			if(search(y[i],b)!=-1)ans+=v[i]*u[search(y[i],b)];
		}
	}
	cout<<ans;
}


2019-12-02 回收站选址

没用什么算法

直译,先判断能否作为回收站,然后判断能得几分,用f[]记录各个分数的回收站个数

#include<bits/stdc++.h>
using namespace std;
#define forn(i,n) for(int i=0;i<n;i++)
int n;
int f[5]={0};
struct point{
    int x,y;
}p[1005];
bool find(int x,int y){
    forn(i,n){
        if(p[i].x==x&&p[i].y==y)
        return 1;
    }
    return 0;
}
int main(){
    cin>>n;forn(i,n){cin>>p[i].x>>p[i].y;}
    forn(i,n){
        if(find(p[i].x-1,p[i].y)&&find(p[i].x,p[i].y+1)
        &&find(p[i].x+1,p[i].y)&&find(p[i].x,p[i].y-1)){
            int c=0;
            if(find(p[i].x-1,p[i].y-1))c++;
            if(find(p[i].x-1,p[i].y+1))c++;
            if(find(p[i].x+1,p[i].y+1))c++;
            if(find(p[i].x+1,p[i].y-1))c++;
            f[c]++;
        }
    } 
    forn(i,5)cout<<f[i]<<'\n';
}


2019-09-2 小明种苹果(续)

没用什么算法

直译

#include<bits/stdc++.h>
using namespace std; 
#define int long long 
int m,n;
int a[1005],b[1005]={0};
bool flag[1005]={0};
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n;
    int total=0,e=0,d=0;
    for(int i=0;i<n;i++)
    {   int m;
        cin>>m;
        cin>>a[i];
        for(int j=1;j<m;j++)
            {
             int tmp;
             cin>>tmp;
             if(tmp<=0)a[i]+=tmp;
             else
             {
                if(tmp<a[i])flag[i]=1;
                a[i]=tmp;
             }                     
            }
        total+=a[i];
        if(flag[i])d++;
        if(i>=1&&i<=n-1&&flag[i]&&flag[i-1]&&flag[i-2])
        e++;       
    } 
    if(flag[0]&&flag[1]&&flag[n-1])
    e++;
    if(flag[n-2]&&flag[0]&&flag[n-1])
    e++;
    cout<<total<<" "<<d<<" "<<e;
}

### 关于 CCF CSP 第36次考试的信息 #### 考试概述 CCF CSP(中国计算机学会-计算机软件能力认证)是一项评估个人编程能力和算法设计水平的权威认证考试。根据以往规律,每年会举办多次 CSP 认证考试,每次考试的具体安排会在考前由 CCF 官方网站或通知公告中发布[^1]。 #### 考试时间 关于第36次 CSP 考试的具体日期,在官方未正式公布之前无法确切得知。然而,基于历史记录,CSP 的考试频率通常是每两个月一次,因此可以根据最近的一次考试推算出大致时间范围。例如,如果最近一次考试是在某个月份举行,则下一次考试可能在之后的两到三个月内进行。 #### 考试内容 CSP 考试主要考察选手对基础算法的理解以及实际编码的能力。目通常分为若干道,难度逐级增加。对于较难的目,如最后一,往往涉及高级数据结构的应用,比如线段树、平衡树等,并且需要结合多种算法技巧才能高效解决[^3]。 #### 成绩查询 CCF CSP 的成绩一般会在考试结束后的几周内在其官方网站上开放查询功能。考生可以通过登录自己的账号查看详细的得分情况及排名信息。值得注意的是,CSP 提供了多次提交的机会,并以最高得分为最终成绩,这给予了参与者更多的灵活性去优化解决方案。 ```python def example_code(): # 这是一个简单的例子展示如何处理二维数组计算邻域均值 matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] def calculate_mean(matrix, row, col): total_sum = sum([matrix[i][j] for i in range(max(0,row-1),min(len(matrix),row+2)) for j in range(max(0,col-1),min(len(matrix[0]),col+2))]) count = sum([1 for i in range(max(0,row-1),min(len(matrix),row+2)) for j in range(max(0,col-1),min(len(matrix[0]),col+2))]) return total_sum / count result_matrix = [[calculate_mean(matrix,i,j) for j in range(len(matrix[0]))] for i in range(len(matrix))] return result_matrix ``` 上述代码片段展示了针对某一类问——即矩阵操作中的“邻域均值”的一种实现方式。此方法虽然简单易懂,但在面对大规模输入时可能存在性能瓶颈,正如某些情况下仅能通过部分测试用例所反映出来的情况一样[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值