CSP备赛(自用笔记)

总结

如果出现非满分(80,90),则考虑边界问题,理解题意问题,样例说明问题。以分蛋糕为例

编译环境为C++11

流程:

1、仔细读题

参数初始化:类型是int还是double,值为0还是数组首元素

如何遍历:由行到列 OR 由列到行,

遍历条件:起始和终止位置

数据更新:覆盖OR开辟

如何计算:手算一遍,写计算式

几个标记元素:由题目得出,特殊的循环遍历方式会用到

2、例子特殊元素,边界问题

3、草稿演算

4、出现运行错误,则检查数组是否越界,数组大小是否正确,循环是否正确(是否出现死循环,循环的条件范围是否正确)

5、出现错误,则检查思路,或者数组太小

6、本地测试样例时,结果和题目要求不同时可以少测一组数据

题目要求: 少测一组:

可以得出本地程序少考虑了哪种情况

7、数组空间往大了开

8、const int MAX=0x3f3f3f3f初始化无穷大

9、比较复杂的判断时可以写函数,例如(仓库规划)

10、谨慎使用continue,break,&&(可以改写成if括号体内写if{}),||

11、90分(非满分时)可以重新梳理一遍,也就是一句一句复杂到main函数里

字符(char)转整数(int)

char c = '6'; //字符型 c = '6'
int num = c - '0'; //转换结果:num = 6

整数(int)转字符(char)

int num = 5; //整型 num = 5
char c = num + '0'; //转换结果:字符型 c = '5'

 字符串(string)转整数(int)

#include <cstring> //需要引入cstring头文件

string = "123456"
int n = stoi(str); //转换为整型 n = 123456(转换失败时发生异常)
int n = atoi(str); //转换为整型 n = 123456(转换失败时返回0)

string = "123456.123"
double d = stof(str); //转换为浮点数 d = 123456.123(转换失败时发生异常)
double d = atof(str); //转换为浮点数 d = 123456.123(转换失败时返回0)

整数(int)转字符串(string)

#include <string> //需要引入string头文件

//基本数据类型均可转换
int num = 123456
string str = to_string(num); //转换为字符串 str = "123456"

跳出两层循环

bool flag = true;
for (int i = 0; i < 5 && flag == true; i++)
{
    for (int j = 0; j < 5 && flag == true; j++)
    {
        cout << "i = " << i << " j = " << j << endl; 
        if (i == 3 && j == 5)
            flag = false;
    }
}

第一题

仓库规划 (90分一次)

//写一个判断是否比它大的函数
//写一个按行到列的遍历
//二维数组存储
#include<iostream>
using namespace std;
	int n,m;//行,列
		int arr[2020][2020];
void fun(int h){
	for(int i=1;i<=n;i++){
		for(int j=0;j<m;j++){
			if(arr[h][j]>=arr[i][j]){
				break;
			}
			if(j==m-1){
				cout<<i<<endl;
				return ;
			}
		}
		if(i==n){
			cout<<0<<endl;
		}
	}
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=0;j<m;j++){
			arr[i][j]=0;
			cin>>arr[i][j];
		}
	}
	for(int i=1;i<=n;i++){
		fun(i);
	} 
	return 0;
} 

90分:不清楚原因(一下是第二遍得90分后修改的满分)

#include<iostream>
using namespace std;
int arr[2010][2010]={0};
int n,m;
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>arr[i][j];
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(j!=i){
				for(int k=1;k<=m;k++){
					if(k==m){
						if(arr[j][k]>arr[i][k]){
							cout<<j<<endl;
							j=n+1;
						}
					}
					if(arr[j][k]<=arr[i][k]){
						break;
					}
				}
			}
			if(j==n){
				cout<<0<<endl;
			}	
		}
	}
	return 0;
}

 坐标变换(其一)(秒杀)

//将每个操作数的每一列都加起来 
//遍历起始点
//二维数组储存,操作数n为行,2为列 ;起始点m为行,2为列
#include<iostream>
using namespace std;
int n,m;
int l=0;//操作数x(左边一列)之和 
int r=0;//操作数y(右边一列)之和 
int arr[2020][2020];//操作数
int Arr[2020][2020];//起始点 
int main(){
	cin>>n>>m;
	for(int i=0;i<n;i++){
		for(int j=0;j<2;j++){
			cin>>arr[i][j];
		}
	}
	for(int i=0;i<m;i++){
		for(int j=0;j<2;j++){
			cin>>Arr[i][j];
		}
	}
	
	for(int i=0;i<2;i++){
		for(int j=0;j<n;j++){
			if(i==0){
				l+=arr[j][i];
			}
			if(i==1){
				r+=arr[j][i];
			}
		}
	}
	for(int i=0;i<m;i++){
		for(int j=0;j<2;j++){
			if(j==0){
				Arr[i][j]+=l;
			}
			if(j==1){
				Arr[i][j]+=r;
			}
		}
	}
	for(int i=0;i<m;i++){
		for(int j=0;j<2;j++){
			cout<<Arr[i][j]<<" ";
			if(j==1){
				cout<<endl;
			}
		}
	}
	return 0;
} 

总结:非常愚蠢的方法        

忘记cin>>n>>m(?)

第二遍:

#include<iostream>
using namespace std;
int n,m;
int dx,dy;
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		int left,right;
		cin>>left>>right;
		dx+=left;
		dy+=right;
	}
	for(int j=1;j<=m;j++){
		int x,y;
		cin>>x>>y;
		cout<<dx+x<<" "<<dy+y<<endl;
	}
	return 0;
}

重复局面(秒杀)(保存数据时注意)

 

 

//字符串数组储存
//整数数组储存答案 
//遍历判断是否相同,相同则整数数组对应位+1
#include<iostream>
using namespace std;
int n;
string str[2020];//字符串数组 
int ans[2020];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		ans[i]=1;
	} 
	for(int i=1;i<=n;i++){
		for(int j=1;j<=64;j++){
			char c;
			cin>>c;
			str[i]+=c;//字符连接成字符串 
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++){//核心j<=i;不是遍历每个元素,而是逐渐累加遍历 
			if(i==j){
				continue;
			}
			if(str[i]==str[j]){
				ans[i]++;
			}
		}
	}
	for(int i=1;i<=n;i++){//将i<=n写成i<=8 
		cout<<ans[i]<<endl;
	}
	return 0;
} //从Dev复制到答题界面时忘记复制}导致编译出错 

总结:1、如何定义一个字符串数组

2、如何将字符连接成字符串

3、核心j<=i;不是遍历每个元素,而是逐渐累加遍历

4、将i<=n写成i<=8导致0分(愚蠢)

5、从Dev复制到答题界面时忘记复制 } 导致编译出错

第二遍:

#include<iostream>
using namespace std;
string C[200];
char c;
int n;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=64;j++){
			cin>>c;
			C[i]+=c;
		}
	}
	for(int i=1;i<=n;i++){
		int ans=1;
		for(int j=1;j<i;j++){
			if(C[i]==C[j]){
				ans++;
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

田地丈量(秒杀)

//四个一维数组储存点坐标
//int ans+=面积 
//竖着遍历(从左上到左下再到右上然后右下)
//x2-x1=x,y2-y1=y最后 x*y算出面积
#include<iostream>
using namespace std;
int x1[2020],y1[2020],x2[2020],y2[2020];
int ans;
int n,a,b;//n块地,(a,b)右上坐标 
int main(){
	cin>>n>>a>>b;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=4;j++){
			if(j==1){
				cin>>x1[i];
			}
			if(j==2){
				cin>>y1[i];
			}
			if(j==3){
				cin>>x2[i];
			}
			if(j==4){
				cin>>y2[i];
			}
		}
	}
	for(int i=1;i<=n;i++){
		if(x1[i]>a){
			x1[i]=a;
			}else if(x1[i]<0){
			x1[i]=0;
				}
		
		if(y1[i]>b){
			y1[i]=b;
			}else if(y1[i]<0){
			y1[i]=0;
				}
		
		if(x2[i]>a){
			x2[i]=a;
			}else if(x2[i]<0){
			x2[i]=0;
				}
				
		if(y2[i]>b){
			y2[i]=b;
			}else if(y2[i]<0){
			y2[i]=0;
				}
	}
	for(int i=1;i<=n;i++){
		ans+=(x2[i]-x1[i])*(y2[i]-y1[i]);
	}
	cout<<ans;
	return 0;
} 

总结:忘记cout<<ans

思路:如何存数据、如何处理数据到新的地方还是覆盖、如何遍历、如何求结果。

第二遍:

#include<iostream>
using namespace std;
int x1[110],y1[110],x2[110],y2[110];
int n;
int r,up;
int ans;
int main(){
	cin>>n;
	cin>>r>>up;
	for(int i=1;i<=n;i++){
		cin>>x1[i]>>y1[i]>>x2[i]>>y2[i];
		if(x1[i]<0){
			x1[i]=0;
		}else if(x1[i]>r){
			x1[i]=r;
		}
		if(y1[i]<0){
			y1[i]=0;
		}else if(y1[i]>up){
			y1[i]=up;
		}
		if(x2[i]<0){
			x2[i]=0;
		}else if(x2[i]>r){
			x2[i]=r;
		}
		if(y2[i]<0){
			y2[i]=0;
		}else if(y2[i]>up){
			y2[i]=up;
		}
		ans+=(x2[i]-x1[i])*(y2[i]-y1[i]);
	}
	cout<<ans;
	return 0;
}

现值计算 (秒杀)

//int n,double i分别表示年数和银行年利率
// double num【2020】//每年的收支
//覆盖数据
//公式分别计算每年的当前价值
//double ans+=每年的当前价值
#include<iostream>
using namespace std;
int n;
double i,ans;
int count[2020];
double num[2020];
int main(){
	cin>>n>>i;
	for(int j=0;j<=n;j++){
		cin>>num[j];
	}
	
	for(int k=1;k<=n;k++){	
		for(int l=1;l<=k;l++){
			num[k]=num[k]/(1+i);//核心:第一年需要除一次,第二年需要除两次,依次累加 
			}
	}
	
	for(int m=0;m<=n;m++){
		ans+=num[m];
	}
	cout<<ans;
	return 0;
} 

总结:理解不清题意时,需要模拟手算一遍数据,慢慢看题,寻找规律。

第一遍思路计算:-200*(1+0.05)*(1+0.05)+100/(1+0.05)+100/1

第二遍思路计算:-200 +100/(1+0.05)+ 100 /(1+0.05)/(1+0.05)

其实-200不用动

第二遍:

#include<iostream>
using namespace std;
double n,m;
double ans;
int main(){
	cin>>n>>m;
	cin>>ans;
	for(int i=1;i<=n;i++){
		double flag;
		cin>>flag;
		for(int j=1;j<=i;j++){
			flag=flag/(1+m);
		}
		ans+=flag;
	}
	cout<<ans;
	return 0;
}

如此编码(秒杀,演算一遍过)

 

 

 

//int n,m分别表示题目数量和数字
//int ans[2020]答案数组,顺序输出
//int ai[2020],bi[2020],ci[2020]
//找最优值循环(核心);类似背包问题 
#include<iostream>
using namespace std;
int n,m;
int ans[2020];
int ai[2020],bi[2020],ci[2020];
int main(){
	cin>>n>>m;
	
	for(int i=1;i<=n;i++){
		cin>>ai[i];
	}
	ci[1]=1;
	for(int i=2;i<=n;i++){
		ci[i]=ci[i-1]*ai[i-1];
	}
	
	for(int i=n;i>=1;i--){
		bi[i]=m/ci[i];//核心:小数学问题 
		m=m-bi[i]*ci[i];
	}
	for(int i=1;i<=n;i++){
		cout<<bi[i]<<" ";
	}
	return 0;
} 

 总结:每次都写成

	for(int i=7;i>=1;i--){
		bi[i]=m/ci[i];//核心:小数学问题 
		m=m-bi[i]*ci[i];
	}

而不是

	for(int i=n;i>=1;i--){
		bi[i]=m/ci[i];//核心:小数学问题 
		m=m-bi[i]*ci[i];
	}

 应该注意循环内的条件

第二遍:

#include<iostream>
using namespace std;
int n,m;
int a[30];
long c[30];
long ans[30];
int main(){
	cin>>n>>m;
	c[1]=1;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(i!=1){
			c[i]=c[i-1]*a[i-1];
		}
	}
	for(int i=n;i>=1;i--){
		if(m>=c[i]){
			ans[i]=m/c[i];
			m=m-ans[i]*c[i];
		}
	}
	for(int i=1;i<=n;i++){
		cout<<ans[i]<<" ";
	}
	return 0;
}

归一化处理(秒杀)(数组开小了导致90分一次)

//整数数组储存
//方差数组
//答案数组 
//一个for循环遍历 
//带入公式计算放入答案数组
//double类型 
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int n;//n个数 
double Number[2020];//初始值 
double average;//平均数 
double var;//方差
double ans[2020];//答案 
double sum=0;//求和除以n得平均数 
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>Number[i];
		sum+=Number[i];
	}
	
	average=sum/n;
	sum=0;
	
	for(int i=1;i<=n;i++){
		sum+=(Number[i]-average)*(Number[i]-average);
	}
	
	var=sum/n;
	
	for(int i=1;i<=n;i++){
		Number[i]=(Number[i]-average)/(sqrt(var));
		cout<<Number[i]<<endl;
	}
	
	return 0;
} 

 第二遍

#include<iostream>
#include<cmath>
using namespace std;
int n;
double arr[1010];
double pj;
double fc;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>arr[i];
		pj+=arr[i];
	}
	pj=pj/n;
	
	for(int i=1;i<=n;i++){
		fc+=(arr[i]-pj)*(arr[i]-pj);
	}
	fc=fc/n;
	
	for(int i=1;i<=n;i++){
		double ans=(arr[i]-pj)/sqrt(fc);
		printf("%f ",ans);
	}
	return 0;
}

总结:double类型而不是int类型(第一遍上来直接写了int) 

未初始化警告(注意看题)(学会调试数据)

标记数组形式: 

//int n,k分别表示变量的数量和赋值语句的条数
//一个标记数组
//一个答案ans 
//一个for循环,k为限制
#include<iostream>
using namespace std;
int n,k;
int ans=0;
bool flag[100020];
int main(){
	cin>>n>>k;
	for(int i=1;i<=k;i++){
		int l=0;//左边值 
		int r=0;//右边值
		cin>>l>>r;
		if(r==0){
			flag[l]=true;
			continue;//考虑常量0 
		}
		if(flag[r]==false){//注意顺序 
			ans=ans+1;
		}
		 flag[l]=true;
	}
	cout<<ans;
	return 0;
}

key-value形式: 

#include<iostream>
using namespace std;
int ans=0;
int arr[100010][1]={0};
int n;
int count;
int main(){
	cin>>n>>count;
	for(int i=1;i<=count;i++){
		int left;
		int right;
		cin>>left>>right;
		if(right==0){
			arr[left][0]++;
			if(i!=count){
				continue;
			}
			
		}
		if(right!=0&&arr[right][0]==0){
			ans++;
			arr[left][0]++;
		}else{
			arr[left][0]++;
		}
	}
	cout<<ans;
	return 0;
}

总结:考虑问题不全面(没考虑常量0),导致结果比预期多1

问题:出现运行错误

解决:数组越界,数组开太小,题目要求10的5次方,则应该开100000

注意看题

注意考虑判断条件的顺序 

序列查询(一遍过,但有心理压力)

 

总结:

第一遍犯病: 最后一个为0的

                   解决:缺少一个边界条件去判断如果i大于序列的最后一个数时,f(i)= n

出现超时:不看子任务要求和提示(即不完整理解题意)

                 解决:看提示

轻敌:解决:仔细看题,演算一遍

单个例子正确,不能AC:解决:循环条件,循环体的参数不对

错误代码:

#include<iostream>
using namespace std;
int n,N;
int num[2020];
int flag;
int index=1;
int ans;
int count;
int main(){
	cin>>n>>N;
	num[0]=0;
	for(int i=1;i<=n;i++){
		cin>>num[i];
	}
	
	for(int i=0;i<N;i++){
		if(i==num[index]){
			ans+=(i-flag)*num[flag];//参数不对,计算式不对 
			index++;
			flag=i;
			count++;
		}
		if(i==N-1){
			ans+=(i-flag+1)*num[flag];//参数不对 ,计算式不对 
		}
	}
	cout<<ans;
	return 0;
} 

没有思路,不知道如何循环遍历:解决设置标记参数;如flag,index,count 

AC代码: 

//int n,N 数组里有n个数,for从0到N遍历 
//int num【】数组 
//int flag作为标记,ans+=(N-flag)*num【flag】,flag=N
//int index当遍历数等于数组数时index++ 
#include<iostream>
using namespace std;
int n,N;
int num[2020];
int flag;
int index=1;
int ans;
int count;
int main(){
	cin>>n>>N;
	num[0]=0;
	for(int i=1;i<=n;i++){
		cin>>num[i];
	}
	
	for(int i=0;i<N;i++){
		if(i==num[index]){
			ans+=(i-flag)*count;
			index++;
			flag=i;
			count++;
		}
		if(i==N-1){
			ans+=(i-flag+1)*count;
		}
	}
	cout<<ans;
	return 0;
} 

第二遍:

#include<iostream>
using namespace std;
int n,N;
int arr[500]={0};
int index=1;
int flag=0;
int count=0;
int ans=0;
int main(){
	cin>>n>>N;
	for(int i=1;i<=n;i++){
		cin>>arr[i];
	}
	for(int j=1;j<N;j++){
		if(j==arr[index]){
			ans+=(j-flag)*count;
			index++;
			count++;
			flag=j;
		}
		if(index>n){
			ans+=((N-1)-flag+1)*count;
			j=N;
		}
	}
	cout<<ans;
	return 0;
} 

 

数组推导(小卡)

//int n,n个数
//int num[100010]存数 
//int max记录最大前缀
//int smax,smin答案:最大最小值
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int n;
int num[100010];

int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>num[i];
	}
	int max=num[0];//初始值(关键) 
	int smax=num[0];
	int smin=num[0];
	for(int i=1;i<=n-1;i++){
		if(num[i]<=max){
			smax=smax+max;
		}else {
			smax+=num[i];
			smin+=num[i];
			max=num[i];
		}
	}
	cout<<smax<<endl<<smin;
	return 0;
} 

参数初始化错误

原因:先入为主的认定例子中的数据(照着例子写程序)                        

解决:提交结果为错误时,思考特殊元素,边界问题

灰度直方图(秒杀)

 

#include<iostream>
using namespace std;
int n,m;
int L;
int num;
int ans[2020];
int main(){
	cin>>n>>m>>L;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			int k=0;
			cin>>num;
			k=num;
			ans[k]++;
		}
	}
	for(int i=0;i<L;i++){
		cout<<ans[i]<<" ";
	}
	return 0;
}

期末预测之安全指数(秒杀)

 

#include<iostream>
using namespace std;
int n;
int ans;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		int left=0;
		int right=0;
		cin>>left>>right;
		ans=ans+left*right;
	}
	if(ans<=0){
		cout<<0;
	}else{
		cout<<ans;
	}
	return 0;
}

称检测点查询(小卡)

 

碰到一些如果没有遍历到结果就输出某一值会卡顿

比如这题:假如数组里都为1(距离都相同),则我们应该输出前三位(输出序号最小的):1 2 3

如仓库规划:如果仓库 i 没有上级,则输出0。

解决:在数组遍历完后加一循环或者判断找答案。

线性分类器(卡住了,可重做)(练习vector)

 

解题思路
容易想到只要把点的坐标带入方程看结果与0的大小可以判断出点在直线左侧还是右侧。

对于每一个方程(直线),判断的过程如下:

记录下每个点的信息(包括哪一类),判断的时候先计算第一个点位于直线左边还是右边,然后看剩余的点是否和第一个点同类别:

如果同类别,那么该点应该和第一个点在直线同一边
如果不同类别,那么该点应该和第一个点分处于直线两侧

注意点
题目中提到方程的三个参数的绝对值 <=10^6,那么把点代入的过程中即源代码中的第13和16行处的r , r e s r, resr,res需要用long long型。

如果写成int型,测评结果为0分。

#include<iostream>
using namespace std;
const int maxn = 1010;
int n, m;
struct point{
	int x, y;
	bool flag; // A类为true,B类为false 
}points[maxn];
int a, b, c; // 方程的三个参数 
bool solve(){
	// 用第一个点区分A类,B类在直线的哪一边 
	long long r = a+b*points[0].x+c*points[0].y;
		 
	for(int i=1; i<n; i++){
		long long res = a+b*points[i].x+c*points[i].y;
		if(points[i].flag == points[0].flag){
			// 和第一个点同类别
			if(r*res < 0) 
				return false; // 异号,同类的点不在直线同一边 
		}
		else{
			// 和第二个点不同类别
			if(r*res > 0)
				return false; // 同号,不同类的点在直线同一边 
		} 
	}
	return true; 
}
int main(){
	cin>>n>>m; 
	int x, y;
	char type; 
	for(int i=0; i<n; i++){
		cin>>points[i].x>>points[i].y>>type;
		if(type == 'A'){
			points[i].flag = true;
		}
		else 
			points[i].flag = false;
	}
	for(int i=0; i<m; i++){
		cin>>a>>b>>c;
		if(solve()){
			printf("Yes\n");
		}	
		else{
			printf("No\n");
		}
	}
	return 0;
} 

字符A是17

1、储存类型为结构体

2、以第一个点的符号正负,类型为标记

3、写出确切的解题思路,过程

第二遍(vector版)

#include<iostream>
#include<vector>
using namespace std;
int n,m;
int arr[1010][1010];
char type[1010];
vector<char> Left;
vector<char> Right;
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>arr[i][0]>>arr[i][1]>>type[i];
	}
	for(int j=1;j<=m;j++){
		int o1,o2,o3;
		cin>>o1>>o2>>o3;
		Left.clear();
		Right.clear();
		for(int k=1;k<=n;k++){
			if(o1+arr[k][0]*o2+arr[k][1]*o3<0){
				Left.push_back(type[k]);
			}
			if(o1+arr[k][0]*o2+arr[k][1]*o3>0){
				Right.push_back(type[k]);
			}
		}
		bool isLeftSame = true;
        for (int l = 1; l < Left.size(); l++) {
            if (Left[l] != Left[l - 1]) {
                isLeftSame = false;
                break;
            }
        }
        bool isRightSame = true;
        for (int l = 1; l < Right.size(); l++) {
            if (Right[l] != Right[l - 1]) {
                isRightSame = false;
                break;
            }
        }
        if (isLeftSame && isRightSame) {
            cout << "Yes" << endl;
        } else {
            cout << "No" << endl;
        }
	}
	return 0;
} 

报数

 出现的问题:两个样例都通过,答案却只有80分

解决:

        边界问题:将while(i!=count)改成while(i!=count+1)

//写一个判断是不是7的倍数,含不含有7,有则返回false
//int ans[4]作为答案
//循环条件:while(i!=count) 
#include<iostream>
using namespace std;
int ans[4]={0,0,0,0};
int i=1;
int count=0;
bool judge(int i){
	if(i%7==0){
		return true;
	}
	while(i!=0){
		int flag=i%10;
		if(flag==7){
			return true;
		}
		i=i/10;
	}
	return false;
}
int main(){
	cin>>count;
	while(i!=count+1){
		if(i%4==1&&judge(i)){
			ans[0]++;
			count++;
		}else if(i%4==2&&judge(i)){
			ans[1]++;
			count++;
		}else if(i%4==3&&judge(i)){
			ans[2]++;
			count++;
		}else if(i%4==0&&judge(i)){
			ans[3]++;
			count++;
		}
		i++;
	}
	for(int i=0;i<4;i++){
		cout<<ans[i]<<endl;
	}
	return 0;
}

 小明种苹果(秒杀)(答案与序号和数相关)

//遍历二维数据全部元素相加为第一个答案
//行号为第二个答案,比较右边最大的数为第三个答案
#include<iostream>
#include<cmath>
using namespace std;
int n,m;
int arr[1010][1010];
int a1=0;
int num[1010]={0};
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m+1;j++){
			cin>>arr[i][j];
			if(j>=2){
			num[i]+=arr[i][j];
			}
			a1+=arr[i][j];
		}
	}
	int flag=num[1];
	int index=1;
	for(int i=2;i<=n;i++){
		if(num[i]<flag){
			flag=num[i];
			index=i;
		}
	}
	cout<<a1<<" "<<index<<" "<<abs(flag);
	return 0;
} 

关键: 

如果两棵树的疏果个数均为4,应该输出编号最小的第1棵树。

小中大(30分,重做)(类型转换int,double)

 

未仔细看题,漏了对于整数请直接输出整数,对于可能出现的分数请输出四舍五入保留1位小数的结果。

错误版

#include<iostream>
#include<algorithm>
using namespace std;
int flag;
int arr[100100]={0};
double ans;
int main(){
	cin>>flag;
	arr[0]=0;
	for(int i=1;i<=flag;i++){
		cin>>arr[i];
	}
	sort(arr+1,arr+flag);
	
	cout<<arr[flag]<<" ";
	
	if(flag%2==0){
		int index=flag;
		for(int j=1;j<=flag;j++){
			if(index-j==1){
				if((arr[index]+arr[j])%2!=0){
					ans=(double)(arr[index]+arr[j])/2.0;
					printf("%0.1lf ",ans);
				}else {
					ans=(int)(arr[index]+arr[j])/2;
					printf("%d ",ans);
				}
				break;
			}else index--;
		}
	}else if(flag%2!=0){
		ans=arr[(flag+1)/2];
		cout<<ans<<" ";
	}
	cout<<arr[1];
	return 0;
}

 满分版

#include <iostream>
#include <cstdio>

using namespace std;

const int N = 1e5;
int a[N];

int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
        scanf("%d", &a[i]);

    int mina = a[0], maxa = a[n - 1];
    if(mina > maxa) swap(mina, maxa);
    if(n % 2 == 1) {
        printf("%d %d %d", maxa, a[n / 2], mina);
    } else {
        if((a[n / 2 - 1] + a[n / 2]) % 2 == 1)
            printf("%d %.1lf %d", maxa, (double)((a[n / 2 - 1] + a[n / 2]) / 2.0), mina);
        else
            printf("%d %d %d", maxa, (a[n / 2 - 1] + a[n / 2]) / 2, mina);
    }

    return 0;
}

小明上学(简单秒杀)

 

//有0,1,2,3四种情况
//如果是0直接加
//如果是1直接加
//如果是3且t>0则加0,如果是3且t=0则加红灯
//如果是2则加当前的数再加红灯
//int r红灯,int y黄灯,int g绿灯
//int n几次循环
//int ans答案
#include<iostream>
using namespace std;
int r,y,g;
int n;
int ans=0;
int main(){
	cin>>r>>y>>g;
	cin>>n;
	
	for(int i=1;i<=n;i++){
		int k,t;
		cin>>k>>t;
		if(k==0||k==1){
			ans+=t;
			continue;
		}
		if(k==3&&t==0){
			ans+=r;
			continue;
		}
		if(k==2){
			ans+=t+r;
			continue;
		}
	}
	cout<<ans;
	return 0;
} 

 跳一跳(秒杀)

//三种情况
//遇到0时结束
//遇到1时相加并设flag=1
//遇到2时判断flag是否大于1,如果大于则加上flag并使flag+=2,如果不大于1则加上2并使flag=4
#include<iostream>
using namespace std;
int flag=1;
int ans=0;
int main(){
	while(true){
		int k;
		cin>>k;
		if(k==0)break;
		if(k==1){
			ans+=1;
			flag=1;
		}
		if(k==2){
			if(flag>1){
				ans+=flag;
				flag+=2;
			}
			if(flag==1){
				ans+=2;
				flag=4;
			}
		}
	}
	cout<<ans;
	return 0;
} 

最小差值 (秒杀)

//int index=n指针指向数组最后一个元素
//首先排序 
//先算出当前的差值
//然后算出右边往前一个index-1的差值
//再算出左边往前i+1 的差值
//谁小谁实现
//如果两个一样默认右边往前一个
//三种情况 
#include<iostream>
#include<algorithm>
using namespace std;
int index;
int n;
int arr[1010]={0};
int ans;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>arr[i];
	}
	
	index=n;
	int flag=1;
	sort(arr+1,arr+n+1);
	
	while(true){
		int judge=arr[index]-arr[flag];
		int left=arr[index]-arr[flag+1];
		int right=arr[index-1]-arr[flag];
		
		if(index-flag==1){
			ans=arr[index]-arr[flag];
			break;
		}
		if(left<right){
			flag++;
			continue;
		}else if(left>=right){
			index--;
			continue;
		}
	}
	cout<<ans;
	return 0;
}

打酱油(秒杀)

//三种情况
//N大于等于50则N-=50 ans+=7
//N大于等于30则N-=30 ans+=4
//N小于30则ans+=N/10
#include<iostream>
using namespace std;
int ans=0;
int N;
int main(){
	cin>>N;
	while(true){
		if(N>=50){
			N-=50;
			ans+=7;
			continue;
		}
		if(N>=30){
			N-=30;
			ans+=4;
			continue;
		}
		if(N<30){
			ans+=N/10;
			break;
		}
	}
	cout<<ans;
	return 0;
} 

 分蛋糕(80分,理解题意不全面)

 80分:认为蛋糕可分,其实蛋糕整分

//三种情况
//当前元素和小于k则continue,不够,要下一个 
//当前元素和大于k则当前元素-=k,ans++,够了 
//加上最后一个元素仍小于k,ans++ ,还有剩的 
#include<iostream>
using namespace std;
int n,k;
int arr[1010]={0};
int ans=0;
int count=0; 
int main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>arr[i];
	}
	
	for(int j=1;j<=n;j++){
		count+=arr[j];
		int flag=count-k;
		if(flag>=0){
			ans++;
			count-=k;
		}
		if(j==n&&count!=0){
			ans++;
		}
	}
	cout<<ans;
	return 0;
} 

没有注意到样例说明:加到够了就分(ans++),类似背包问题的整拿整放,不能分开

满分:

//三种情况
//当前元素和小于k则continue,不够,要下一个 
//当前元素和大于k则当前元素-=k,ans++,够了 
//加上最后一个元素仍小于k,ans++ ,还有剩的 
#include<iostream>
using namespace std;
int n,k;
int arr[1010]={0};
int ans=0;
int count=0; 
int main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>arr[i];
	}
	
	for(int j=1;j<=n;j++){
		count+=arr[j];
		if(count>=k){
			ans++;
			count=0;
		}
		if(j==n&&count!=0){
			ans++;
		}
	}
	cout<<ans;
	return 0;
} 

 中间数(90分,想复杂)

90分:

//序列中有相同元素(如5,6,6则大于5的有两个)
//排完序后最左右两边的数不可能是中间数
//不可能有两个中间数 

//奇数个序列数(中间数一定是arr[(n+1)/2]) (三种情况) 
//1、排完序后左小右大(下一个) 
//2、排完序后左等右大(右加一) 
//3、排完序后左小右等(左加一)
//最后判断左边等于右边输出中间数,否则输出-1 

//偶数个序列数(中间数一定是arr[n/2]和arr[n/2+1]) (同上) 
#include<iostream>
#include<algorithm>
using namespace std;
int n;
int arr[1010]={0};
int ans=0;
int judge(){
	int left=0;
	int right=0;
	int lmid=n/2;
	int rmid=n/2+1;
	int flag=rmid+1;
	if(arr[lmid]!=arr[rmid])return -1;
	for(int k=lmid-1;k>=1;k--){
		if(arr[k]<arr[lmid]&&arr[flag]>arr[lmid]){
			if(k==1&&left==right){
			return arr[lmid];
			}else if(k==1&&left!=right){
					return -1;
				}
		flag++;
		continue;
		}
		if(arr[k]==arr[lmid]&&arr[flag]>arr[lmid]){
			right++;
		}
		if(arr[k]<arr[lmid]&&arr[flag]==arr[lmid]){
			left++;
		}
		if(k==1&&left!=right){
			return -1;
		}else if(k==1&&left==right){
			return arr[lmid];
		}
		flag++;
		
	}
}
int Judge(){
	int mid=(n+1)/2;//中间数 
	int left=0;
	int right=0;
	int flag=(n+1)/2+1;
	for(int k=mid-1;k>=1;k--){
		if(arr[k]<arr[mid]&&arr[flag]>arr[mid]){
			if(k==1&&left==right){
				return arr[mid];
			}else if(k==1&&left!=right){
				return -1;
			}
			flag++;
			continue;
		}
		if(arr[k]==arr[mid]&&arr[flag]>arr[mid]){
			right++;
		}
		if(arr[k]<arr[mid]&&arr[flag]==arr[mid]){
			left++;
		}
		if(k==1&&left!=right){
			return -1;
		}else if(k==1&&left==right){
			return arr[mid];
		}
		flag++;
	}
	
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>arr[i];
	}
	sort(arr+1,arr+n+1);
	
	if(n%2==0){//偶数 
		ans=judge();
	}
	if(n%2!=0){//奇数
		ans=Judge(); 
	}
	
	cout<<ans;
	return 0;
}

满分:

#include<bits/stdc++.h>

using namespace std;

int main()
{
    int sma_num = 0;
    int big_num = 0;
    int n;
    cin>>n;
    int num[n];
    for(int i=0; i<n; i++)
        cin>>num[i];
    sort(num,num+n);

    //奇数
    if(n%2 != 0)
    {
        for(int i=0; i<n; i++)
        {
            if(num[i]<num[(n-1)/2])
                sma_num++;
            else if(num[i]>num[(n-1)/2])
                big_num++;
        }
        if(sma_num == big_num)
            cout<<num[(n-1)/2];
        else
            cout<<"-1";
    }
    //偶数
    else
    {
        if(num[(n-1)/2] != num[n/2])
            cout<<"-1";
        else
        {
            for(int i=0; i<n; i++)
            {
                if(num[i]<num[(n-1)/2])
                    sma_num++;
                else if(num[i]>num[(n-1)/2])
                    big_num++;
            }
            if(sma_num == big_num)
                cout<<num[(n-1)/2];
            else
                cout<<"-1";
        }
    }
    return 0;
}

 最大波动(秒杀)

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int n;
int arr[1010]={0};
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>arr[i];
	}
	int max=0;
	for(int j=2;j<=n;j++){
		if(abs(arr[j]-arr[j-1])>max){
			max=abs(arr[j]-arr[j-1]);
		}
	}	
	cout<<max;
	return 0;
}

折点计数(秒杀)

#include<iostream>
using namespace std;
int n;
int arr[1010];
int ans=0;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>arr[i];
	}
	bool down=false;
	bool up=false;
	for(int j=2;j<n;j++){
		if(arr[j]-arr[j-1]>0){
			up=true;
			down=false;
		}else if(arr[j]-arr[j-1]<0){
			up=false;
			down=true;
		}
		if(arr[j+1]-arr[j]>0&&down==true){
			ans++;
		}else if(arr[j+1]-arr[j]<0&&up==true){
			ans++;
		}
	}
	cout<<ans;
}

数位之和(秒杀)

#include<iostream>
using namespace std;
long n;
long ans=0;
int main(){
	cin>>n;
	while(true){
		if(n==0)break;
		ans+=n%10;
		n=n/10;
	}
	cout<<ans;
	return 0;
}

 数列分段(秒杀)

#include<iostream>
using namespace std;
int arr[1010]={0};
int n;
int ans=0;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>arr[i];
	}
	for(int j=1;j<=n;j++){
		if(j==1){
			ans++;
			continue;
		}
		if(arr[j]!=arr[j-1]){
			ans++;
		}else{
			continue;
		}
	}
	cout<<ans;
	return 0;
}
 

稍微考虑一下左右两边边界问题(第一个数时和最后一个数时的情况) 

图像旋转(矩阵转置,秒杀)

#include<iostream>
using namespace std;
int n,m;
int arr[1010][1010]={0};
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>arr[i][j];
		}
	}
	for(int i=m;m>=1;m--){
		for(int j=1;j<=n;j++){
			cout<<arr[j][m]<<" ";
			if(j==n){
				cout<<endl;
			}
		}
	}
	return 0;
} 

门禁系统(秒杀)

#include<iostream>
using namespace std;
int n;
int arr[1010]={0};
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		int flag;
		cin>>flag;
		arr[flag]++;
		cout<<arr[flag]<<" ";
	}
	return 0;
}

 相邻数对(秒杀)

//1个数就输出0
//差1则ans++
//遍历由1到n-1 
#include<iostream>
#include<algorithm>
using namespace std;
int n;
int arr[1010]={0};
int ans=0;
int main(){
	cin>>n;
	if(n==1){
		return 0;
	}
	for(int i=1;i<=n;i++){
		cin>>arr[i];
	}
	sort(arr+1,arr+n+1);
	for(int i=1;i<=n-1;i++){
		if(arr[i+1]-arr[i]==1){
			ans++;
		}
	}
	cout<<ans;
	return 0;
} 

 相反数(秒杀)(考虑最后一次循环的情况)(循环控制结束语句应放在循环体前面)(continue语句有时会使循环无法结束)

//相加等于0则ans++,left+1,right-1
//相加大于0则右边-1
//相加小于0则左边+1
//如果right=left或者right-left=1则break 
#include<iostream>
#include<algorithm>
using namespace std;
int n;
int arr[1000]={0};
int ans=0;
int main(){
	cin>>n;
	if(n==1)return 0;
	int left=1;
	int right=n;
	for(int i=1;i<=n;i++){
		cin>>arr[i];
	}
	sort(arr+1,arr+n+1);
	while(true){
		if(right-left==1 || right==left){
			if(arr[left]+arr[right]==0){
				ans++;
			}
			break;
		}
		if(arr[left]+arr[right]==0){
			ans++;
			left++;
			right--;
			continue;
		}
		if(arr[left]+arr[right]>0){
			right--;
			continue;
		}
		if(arr[left]+arr[right]<0){
			left++;
			continue;
		}
	}
	cout<<ans;
	return 0;
}

 出现次数最多的数(key-value形式)(可重做)

 使用二维数组表示键值对

#include <stdio.h>

//num[i][0]存储列表中出现的数,num[i][1]记录该数在当前列表中出现的次数
static int num[1001][2]={0};

int main()
{
    int i,j;
    int n,number;
	int max;								//max记录当前列表中出现次数最多的数的出现次数
	int min;								//min记录当前列表中出现次数最多的数中的最小的数
	
    scanf("%d",&n); 
   
    for(i=0;i<n;i++)
    {
        scanf("%d",&number);
        for(j=0;num[j][0]!=0;j++)
		{
			if(num[j][0]==number) break;	//若当前列表中有该元素,跳出循环
		}
        if(num[j][0]==0) num[j][0]=number;	//若当前列表中没有该元素,添加该元素到列表尾部
        num[j][1]++;						//当前元素出现的次数加一
		if(i==0) max=num[0][1],min=num[0][0];	//i等于0时,初始化max和min
		else
		{
			//若当前元素的出现次数比上一次记录的出现次数最多的数多,更新max和min
			if(num[j][1]>max) max=num[j][1],min=num[j][0];
			//若当前元素的出现次数等于上一次记录的出现次数最多的数,并且该数比上一次记录的出现次数最多的数小,更新min
			else if(num[j][1]==max&&num[j][0]<min) min=num[j][0];
		}
    }

    printf("%d\n",min);
    return 0;
}

 满分:

#include<iostream>
using namespace std;
int arr[10010][2]={0};
int n;
int flag;
int ans=0;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>flag;
		arr[flag][0]=flag;
		arr[flag][1]++;
	}
	int max=-1;
	for(int i=1;i<=10010;i++){
		 if(arr[i][1]>max){
		 	max=arr[i][1];
		 	ans=i;
		 }
	}
	cout<<ans;
	return 0;
}

出现运行错误

原因:答案的范围为1到10000,但是数组和循环只开到了1000,错把一共有几个数当成答案范围

解决:检查数组是否越界,循环是否出错

第二题

ISBN号码

第一遍(50分)

#include<iostream>
using namespace std;
int sum;
int ans[10];
int flag=1;
char s[14];
int main(){
	for(int i=1;i<=13;i++){
		cin>>s[i];
		if(s[i]=='-'){
			continue;
		}else{
			ans[flag]=(int)(s[i]);
			sum+=flag*ans[flag];
			flag++;
		}
	}
	sum=sum%11;
	int index=(int)(s[13]);
	if(sum==index){
		cout<<"Right";
	}else{
		for(int i=1;i<=13;i++){
			cout<<s[i];
		}
	}
	return 0;
}

窗口

第一版  

//没点到输出IGNORED
//点到了一个窗口则输出其序号并将其置顶
//点到了多个窗口则判断谁在上,在上的输出其序号并置顶
//x1,y1,x2,y2数组
//int index序号大的在上
//int N个窗口
//int M次点击
#include<iostream>
using namespace std;
int x1[100],x2[100],y1[100],y2[100];
int index[100];//序号 
int N,M;
int main(){
	cin>>N>>M;
	for(int i=1;i<=N;i++){
		cin>>x1[i]>>y1[i]>>x2[i]>>y2[i];
		index[i]=i;
	}
	for(int i=1;i<=M;i++){
		int x,y;
		cin>>x>>y;
		for(int j=N;j>=1;j--){
			if(x>=x1[j]&&x<=x2[j]&&y>=y1[j]&&y<=y2[j]){
				//输出序号,放到前面
				cout<<index[j];
			}
			if(j==1){
				cout<<"IGNORED"<<endl;
				break;
			}
		}
	}
	return 0;
} 

画图

没思路

解决:求每个不同的方格有几个

#include <iostream>
#include <map>
#include <string>
#include <sstream>

using namespace std;

// 将整数转换为字符串的函数
string itos(int n){
    stringstream tem; // 创建一个字符串流对象
    tem << n; // 将整数n插入到字符串流中
    return tem.str(); // 返回字符串流中的字符串表示
}

int main(){
    int num; // 存储输入的点的数量
    int point[4]; // 用于存储一个矩形的两个对角线点的坐标
    map<string,int> area; // 使用map来存储每个方格出现的次数

    cin >> num; // 输入点的数量
    for(int i = 0; i < num; i++){
        cin >> point[0] >> point[1] >> point[2] >> point[3]; // 输入矩形的两个对角线点的坐标
        // 给的是点,求得是方格
        for(int m = point[0] + 1; m <= point[2]; m++){ // 遍历矩形的x坐标
            for(int n = point[1] + 1; n <= point[3]; n++){ // 遍历矩形的y坐标
                string key = itos(m) + "-" + itos(n); // 创建方格的唯一标识符,格式为"x-y"
                ++area[key]; // 方格出现次数加1
            }
        }
    }

    cout << area.size(); // 输出不同方格的总数

    return 0;
}
 

Z字形扫描

//设置flag=true时,x--,y++
//设置flag=false时,x++,y--
//判断如果下一个结点越界则根据flag选择
//true时y++,false时,x++ 且变换flag
//如果结点为(n,n)则输出并退出
#include<iostream>
using namespace std;
bool flag=true;
int arr[510][510]={0};
int x=1;
int y=1;
int n;
bool judge(){
	if(flag==true&&x-1==0){
		flag=false;
		y++;
		return false;
	}else if(flag==false&&y-1==0){
		x++;
		flag=true;
		return false;
	}else return true;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cin>>arr[i][j];
		}
	}
	while(true){
		if(x==n||y==n){
			break;
		}
		cout<<arr[x][y]<<" ";
		if(judge()){
			if(flag==true){
				x--;
				y++;
				continue;
			}else if(flag==false){
				x++;
				y--;
				continue;
			}
		}else continue;
	}
	cout<<arr[n][n];
	return 0;
} 

  • 30
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
青少年csp编程初赛是一项非常重要且有趣的比赛。参加比赛的过程中,我学到了很多知识和技巧,积累了宝贵的编程经验。 首先,我要提到的是算法。在比赛中,我们需要解决各种问题,而高效的算法是解决问题的关键。我学到了许多常用的算法,并且学会了如何根据问题的特点来选择合适的算法。比如,我了解到了搜索算法和贪心算法,在解决问题时能够更快地找到最优解。 其次,比赛还提高了我的编程能力。在比赛中,我们需要用特定的编程语言来实现算法和解决问题。通过参赛,我不仅熟练掌握了基本的编程语法,还学会了如何灵活运用语言的特性来简化编程过程。我还学到了编程中常用的技巧和思维方式,使我的代码更加清晰、高效。 此外,参加比赛还提升了我的团队合作能力。在初赛中,我和队友一起解决问题,共同思考和讨论最优解。我们互相帮助、合理工,充发挥每个人的优势,最终取得了不错的成绩。团队合作的经验对我来说非常宝贵,将对我今后的学习和工作都有很大的帮助。 通过参加青少年csp编程初赛,我不仅学到了知识和技巧,还培养了自己的解决问题的能力和团队合作意识。这次经历不仅让我在编程方面有所提升,也对我的成长有着深远的影响。我将继续努力学习和提升自己,在编程领域取得更好的成绩。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值