CCF血泪史

1.201909-1小明种苹果

这里是引用在这里插入图片描述在这里插入图片描述

这个题一定要注意,大数组不能直接定义在main函数中,要定义在main函数之外作为全局变量,全局变量在静态存储区分配内存,局部变量是在栈上分配内存空间的。(c语言程序在运行时会动态创建一个堆栈段,里面存放着调用栈,保存着函数的调用关系和局部变量。)如果数组太大,可能会造成栈溢出。

#include <iostream>
using namespace std;
long long a[1001][1001];
int main()
{
	int n,m;
	cin>>n>>m;
	long long T=0,K=0,P=-1,sum=0,num=0;
	for(int i=0;i<n;i++)
	{
		num=0;
		for(int j=0;j<m+1;j++)
		{
			cin>>a[i][j];
			if(j) num-=a[i][j];
		}
		sum+=a[i][0]-num;
		if(P<num)
		{
			P=num;
			K=i+1;
		}
	}
	cout<<sum<<' '<<K<<' '<<P; 
	return 0;
}

不定义成全局变量还可以用new来动态开辟二维数组,new是从自由存储区为对象动态分配内存的,也不会造成栈溢出。

#include <iostream>
using namespace std;
int main()
{
	int n,m;
	cin>>n>>m;
	long long **a=new long long *[1001];
	for(int i=0;i<1001;i++) a[i]=new long long[1001];
	long long T=0,K=0,P=-1,sum=0,num=0;
	for(int i=0;i<n;i++)
	{
		num=0;
		for(int j=0;j<m+1;j++)
		{
			cin>>a[i][j];
			if(j) num-=a[i][j];
		}
		sum+=a[i][0]-num;
		if(P<num)
		{
			P=num;
			K=i+1;
		}
	}
	cout<<sum<<' '<<K<<' '<<P; 
	return 0;
}

2.201903-1小中大

这里是引用在这里插入图片描述
1.看错题。这个题真的一定要看清楚题目啊!题中说的是对于可能出现的分数,四舍五入保留一位小数,注意四舍五入保留一位小数中四舍五入的是第二位小数!例如:1.85四舍五入就是1.9,而本身只有一位小数的如1.5四舍五入得2应该描述成:四舍五入到个位!而这道题本来最多就是两个数得和是个奇数,除以2得到的是有一位小数的浮点数,不存在要四舍五入的,直接输出其除出来得到的浮点数即可。
2.当输入的数据为偶数个时,中位数是最中间两个数的和的平均值,当这两个数的和是奇数的时候,如果直接这么写:

med=(double)(a[n/2-1]+a[n/2])/2;
cout<<med;//输出中位数

那么当med这个数据很大的时候,可能会以科学计数法的形式输出中位数,导致答案错误,例:
在这里插入图片描述
在这里插入图片描述
采用cout的输出或者printf输出都可

#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;
int main()
{
	int n,judge=0,max,min;
	double med;
	cin>>n;
	int a[n];
	for(int i=0;i<n;i++) cin>>a[i];
	sort(a,a+n);
	max=a[n-1];
	min=a[0];
	if(n%2)  med=a[(n-1)/2];
	else if((a[n/2-1]+a[n/2])%2) 
	{
		med=(double)(a[n/2-1]+a[n/2])/2;
		cout<<max<<' '<<setiosflags(ios::fixed)<<setprecision(1)<<med<<' '<<min;
		return 0;
	}
	else med=(a[n/2-1]+a[n/2])/2;
	cout<<max<<' '<<setiosflags(ios::fixed)<<setprecision(0)<<med<<' '<<min;
	return 0;
}

采用printf的输出:一定要表明输出几位小数,直接用printf("%f",med);输出将会默认输出六位小数,例:
在这里插入图片描述

#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
	int n,judge=0,max,min,med;
	cin>>n;
	int a[n];
	for(int i=0;i<n;i++) cin>>a[i];
	sort(a,a+n);
	max=a[n-1];
	min=a[0];
	if(n%2)  med=a[(n-1)/2];
	else if((a[n/2-1]+a[n/2])%2) 
	{
		printf("%d %.1f %d", max, (double)(a[n/2-1]+a[n/2])/2, min);//注意一定要写成%.1f,否则将默认输出6位小数
		return 0;
	}
	else med=(a[n/2-1]+a[n/2])/2;
	printf("%d %d %d",max,med,min);
//或者将med定义double类型,printf("%d %0.f %d",max,med,min);
	return 0;
}

3.201903-2二十四点

这里是引用
在这里插入图片描述
在这里插入图片描述

这道题如果直接暴力解法,将会有64种情况,也可以按照四则运算乘除法优先运算,自左至右依次运算的四则运算法则进行计算。直接暴力解法就是代码稍微长一点,但是运用四则法则进行计算,首先写这个算法就得写一段时间,然后改bug改到心态要崩了,所以如果情况没那么多的时候,可以直接运用暴力解法,可能要更快,但是准确性会更高,把每种情况都测试一遍就ok了。下面给出四则运算方式的代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n,a[4],res;//res记录24点运算结果,a数组的元素为输入的4个数字 
	cin>>n;
	char ch[4],b[4];//ch是符号,为防止+-被读入数字中,先用b数组记录数字,然后再转化为数字的a数组 
	vector<int>prior;//prior记录x/的位置 
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<7;j++)
		{
			if(j%2) //先找到x或者/,记录个数以及它们的位置,0、1、3都好办,2个还要分情况是连乘还是用加号分开的 
			{
				cin>>ch[j/2];
				if(ch[j/2]=='x'||ch[j/2]=='/')
				{
					prior.push_back(j/2); 
				}
			}
			else 
			{
				cin>>b[j/2];//为了防止+或者-被读入数字中 
				a[j/2]=(int)(b[j/2]-'0');
			}
		}
		if(prior.empty()) //全都是+-
		{
			res=a[0];
			for(int j=0;j<3;j++)
			{
				if(ch[j]=='+') res+=a[j+1];
				else res-=a[j+1];
			}
		}
		else if(prior.size()==3)//全都是*/ 
		{
			res=a[0];
			for(int j=0;j<3;j++)
			{
				if(ch[j]=='x') res*=a[j+1];
				else res/=a[j+1];
			}
		}
		else if(prior.size()==1) //只有一个乘 ,出现a-b*c+d怎么办 ? 
		{
			res=a[prior[0]];
			if(ch[prior[0]]=='x') res*=a[prior[0]+1];
			else res/=a[prior[0]+1]; 
			if(prior[0])//如果不是在第一个符号位为*/ 
			{
				if(ch[prior[0]-1]=='-') res=-res;
				res+=a[0];
				for(int j=0;j<3;j++)
				{
					if(j!=prior[0]&&j!=(prior[0]-1))//当j不是*/的位置时 
					{
						if(ch[j]=='+') res+=a[j+1];
						else res-=a[j+1]; 
					}
				}
			}
			else//是在第一个符号位为*/ 
			{
				for(int j=1;j<3;j++)
				{
					if(ch[j]=='+') res+=a[j+1];
					else res-=a[j+1];
				}
			}
		} 
		else if(prior[1]-prior[0]==1) //连乘,出现a-b*c*d怎么办 
		{
			res=a[prior[0]];
			for(int j=prior[0];j<=prior[1];j++) 
			{
				if(ch[j]=='x') res*=a[j+1];
				else res/=a[j+1];
			}
			if(prior[0]) //a-bxcxd
			{
				if(ch[0]=='-') res=a[0]-res;
				else res+=a[0];
			}
			else//axbxc-d 
			{
				if(ch[2]=='-') res-=a[3];
				else res+=a[3];
			}
		}
		else//分开*然后相加 
		{
			if(ch[2]=='x') res=a[2]*a[3];
			else res=a[2]/a[3];
			if(ch[1]=='-') res=-res;
			if(ch[0]=='x') res+=a[0]*a[1];
			else res+=a[0]/a[1];
		}
		if(res==24) cout<<"Yes"<<endl;
		else cout<<"No"<<endl;
		prior.clear(); 
	} 
	return 0;
} 

4.201812-2小明放学

这里是引用在这里插入图片描述

  • 一定一定要注意各个数据的范围!!!k<=1e6,t<=1e6 ,n<=1e5,如果使用int类型的数据会有数据溢出的可能 !!!
  • 一定要看清楚这一题给出的是小明出发的时候,某个路段的红绿灯的剩余秒数,所以要求得小明到达该路段时,该路段是什么颜色的灯以及该灯现在已经亮了多少秒、还剩多少秒,假设红灯亮起的时刻记为0,如果红黄绿灯的时长依次为:30,3,30,红绿灯按:红灯、绿灯、黄灯的顺序循环变换,那么如果给出的第k组数据是3,10,那么在小明出发的时刻,说明其在绿灯阶段,则开始时,该路段的时刻记为30(红灯亮的时间)+30(绿灯亮的时间)-10(绿灯还剩余的时间)=50s,加入经过前k-1个路段花费了ts,那么在到底第k个路段的时候,此时第k个路段的红绿灯状态应该是:令a=(t+50)%(63),看a处在[0,30],[31,60],[61,63)的哪一个时间段,这三个时间段分别对应红灯、绿灯、黄灯,注意如果处在黄灯的时间段,那么等完了黄灯之后还得等红灯,还必须加上红灯段的时间。代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{//注意这个题的数据范围:k<=1e6,t<=1e6 ,n<=1e5,如果使用int类型的数据会有数据溢出的可能 
	long long a[3],n,k,t,sum=0,time=0,med=0,res=0;//sum表示时间的总和,med是一个中间媒介作为工具,res为最终结果
	cin>>a[0]>>a[2]>>a[1];//a0、a1、a2分别表示红灯、绿灯、黄灯的时间 
	sum=a[0]+a[1]+a[2];
	cin>>n;
	while(n--)
	{
		cin>>k>>t;
		if(!k) res+=t;//k=0直接加时 
		else
		{
			if(k==2) k=3;//由于红绿灯是按照红灯、绿灯、黄灯交替,而题目输入的顺序是1红灯,2黄灯,3绿灯,顺序不同,所以对k的顺序作修改,使其与红绿灯变换顺序一致 
			else if(k==3) k=2;
			med=res-t;
			for(long long c=0;c<k;c++) med+=a[c];
			med%=sum;//med表示实时时间段 
			if(med<=a[0]) res+=a[0]-med;//表示其在红灯段
			else if(med>=a[0]+a[1]) res+=sum-med+a[0];//其在黄灯段 
		}
	} 
	cout<<res;
	return 0;
} 

5.201809-1卖菜

这里是引用

这个题一定要检查输出数据的组数,必须与商店的数量一致,有边界样例n=2,注意有两个商店时,不要只算完第一个商店然后第二个商店就不管了,第二个商店也必须要输出相对应的值。
注意边界样例的测试!,代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n;
	cin>>n;
	int a[n];
	for(int i=0;i<n;i++) cin>>a[i];
	cout<<(a[0]+a[1])/2<<' ';
	if(n>2)
	{
		for(int i=1;i<n-1;i++)
		{
			cout<<(a[i-1]+a[i]+a[i+1])/3<<' ';
		}
	}
	cout<<(a[n-2]+a[n-1])/2;
	return 0;
}

6.201809-2买菜

这里是引用

这道题一定要注意时间段和时刻的差别,比如给出的数据中有[13,14],[14,15]这两个时间段,虽然14时刻有重叠,但是实际上两个时间段并不重叠,不能被计入聊天时间种,代码:

#include <bits/stdc++.h>
using namespace std;
int a[1000002]={0};
int main()
{
	int n,s,e,res=0;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>s>>e;
		for(int j=s;j<=e;j++) a[j]=s;
	}
	for(int i=0;i<n;i++)
	{
		cin>>s>>e;
		for(int j=s;j<e;j++) 
		{
			if(a[j]&&(a[j]==a[j+1])) //说明是在一个连续的时间段,除去了 [13 14]  [14 15]同时装车的时候将14时刻也计入到答案中 
			{
				res++;
//				cout<<"J:"<<j<<' '<<j+1<<endl;
			}
		}
	}
	cout<<res;
	return 0;
} 

7.201803-1跳一跳

这里是引用

一定一定一定要认真读题!把题目条件写在程序的注释里或者本子上!自己过一遍!题目的意思是如果跳到了中心,上一次得分为1分或者这是游戏的第一次跳跃,得分才为2分,而不是一开始只要跳上去了不管有没有跳到中心就有2分!代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n,bef,res=0,judge=0,begin=1;//judge表示跳到了2而且是否一直为2,bef表示上一次的得分 
	while(scanf("%d",&n)&&n)
	{
		if(begin)
		{
			bef=n;
			begin=0;
			res+=bef;
			if(n==2) judge=1;
		}
		else
		{
			if(n==1) 
			{
				bef=1;
				judge=0;
				res++;
			}
			else if(n==2)
			{
				if(judge) bef+=2;
				else bef=2;
				res+=bef;
				judge=1;
			}
		}
	}
	cout<<res;
	return 0; 
} 

8.201803-2碰撞的小球

这里是引用在这里插入图片描述在这里插入图片描述

一定要注意给定的每个小球的位置不一定是按照顺序来给的,有可能是乱序,必须对小球的位置按照从小到大的顺序排序去做,将小球按照其位置排序后,即使小球撞墙、互相碰撞,其位置的顺序也不会改变,比如有3个球,位置在中间的球无论怎么撞也不可能到三个球的最左边或者最右边,所以最后求出了按照位置的相对顺序排列的小球的位置后,再将其按照编号排序,输出其位置即可。代码:

#include <bits/stdc++.h>
using namespace std;
struct ball
{
	int pos,judge=0,shunxu;//judge为0 表示向右运动,为1表示向左运动 
};
int cmp1(ball a,ball b)
{
	return a.pos <b.pos ;
}
int cmp2(ball a,ball b)
{
	return a.shunxu <b.shunxu ;
}
int main()
{
	int n,L,t;
	cin>>n>>L>>t;
	ball b[n];
	for(int i=0;i<n;i++) 
	{
		cin>>b[i].pos;
		b[i].shunxu=i;
	}
	sort(b,b+n,cmp1);//按照位置排序 
	while(t--)
	{
		for(int i=0;i<n;i++)
		{
			if(!b[i].judge)//向右运动 
			{
				b[i].pos++;
			}
			else b[i].pos--;
		}
		for(int i=0;i<n-1;i++)
		{
			if(b[i+1].pos==b[i].pos&&!b[i].judge&&b[i+1].judge)
			{
				b[i].judge=1;
				b[i+1].judge=0;
			}
			if(b[i].pos==L) b[i].judge=1;
			else if(b[i].pos==0) b[i].judge=0;
			if(b[i+1].pos==L) b[i+1].judge=1;
			else if(b[i+1].pos==0) b[i+1].judge=0;
		}
//		for(int i=0;i<n;i++) cout<<b[i].pos <<' '; cout<<endl;
	}
	sort(b,b+n,cmp2);
	for(int i=0;i<n;i++) cout<<b[i].pos <<' '; 
	return 0;
}

9.201712-2游戏

这里是引用在这里插入图片描述

一定一定一定要注意数组越界的问题! ,具体看代码注释:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n,k,count=0,j=0;
	cin>>n>>k;
	vector<int>p;
	for(int i=0;i<n;i++) p.push_back(i+1);
	while(p.size()>1)
	{ 
		count++;
		if((count%k==0)||(count%10==k)) //该处小朋友被淘汰 删除元素 
		{
			p.erase(p.begin()+j);//删除元素后,j的值不改变,如果此时删除的是最后一个元素,也就是说j=p.size()-1,设此时p.size()的大小为m,那么删掉了一个元素之后p.size()的值变为m-1,若接下来经历的一次while循环,要接着淘汰一个小朋友,比如本题的7 3样例,12 13是连着的,报了12和13的数小朋友都要被淘汰,此时j的值不变,仍然是m-1,那么运行p.erase(p.begin()+j);的时候就会导致数组越界
		}
		else 
		{
			j++;
			if(j>=p.size()) j=0;
		}
	} 
	cout<<p[0];
	return 0;
} 

所以,应该在每次的while循环之后都要判断一次j>=p.size(),因为if else语句中的if{}和else{}要么会改变j的值,要么改变p.size()的值。代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n,k,count=0,j=0;
	cin>>n>>k;
	vector<int>p;
	for(int i=0;i<n;i++) p.push_back(i+1);
	while(p.size()>1)
	{
//		if(j>=p.size()) j=0;//该语句放这儿也行 
		count++;
		if((count%k==0)||(count%10==k)) //该处小朋友被淘汰 删除元素 
		{
			p.erase(p.begin()+j);
		}
		else 
		{
			j++;
//			if(j>=p.size()) j=0;//语句不能放这里, 有可能在p删除了一个元素之后p.size()减小,但是j的值不变,导致可能造成数组越界,所以这条语句只能放在j++的else语句的外面,不能放里面
		}
		if(j>=p.size()) j=0;//有可能在p删除了一个元素之后p.size()减小,但是j的值不变,导致可能造成数组越界,所以这条语句只能放在j++的else语句的外面,不能放里面 
//		cout<<"count:"<<count<<"j:"<<j<<' ';
//		for(int i=0;i<p.size();i++) cout<<p[i]<<' ';cout<<endl;
	} 
	cout<<p[0];
	return 0;
} 

10.201703-2排队

这里是引用

注意insert函数的使用:

vector<int>a(100);
a.insert(a.begin()+i,p);

是把p插入到a[i]的位置,即a[i]=p,a[i]之后的元素全都往后移,而不是在a[i]之后插入p,即a[i+1]=p,a[i+1]之后的元素全都往后移。代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n,m,p,q,pos;
	scanf("%d%d",&n,&m);
	vector<int>a(n);
	for(int i=0;i<m;i++)
	{
		scanf("%d%d",&p,&q);
		for(int j=0;j<n;j++) 
		{
			if(a[j]==p) 
			{
				pos=j;//找到学号为p的同学的位置 
				if(q>0) 
				{
					a.insert(a.begin()+j+q+1,p);//往后移q个位置,因为该元素还未删除且位置在其要插入位置的前面,再插入一个与该元素相等的值,应该是插入到a[j+q+1]的位置
					a.erase(a.begin()+j);
				}
				else 
				{
					a.insert(a.begin()+j+q,p);
					a.erase(a.begin()+j+1); 
				}
				break;
			}
		}
//		for(int i=0;i<n;i++) printf("%d ",a[i]);
	} 
	for(int i=0;i<n;i++) printf("%d ",a[i]);
	return 0;
}

11.202006-2

在这里插入图片描述

这一题一定一定一定要注意时间复杂度,不要乱用二重循环,当数据过大时极有可能超时!
原代码:

#include<bits/stdc++.h>
using namespace std;
struct dex
{
	long long pos;
	int val;
};
int main()
{
	int n,a,b,vp,vl;
	long long res=0;
	cin>>n>>a>>b;
	dex u[a];
	for(int i=0;i<a;i++) 
	{
		cin>>u[i].pos >>u[i].val;
	}
	for(int i=0;i<b;i++)
	{
		cin>>vp >>vl;
		for(int j=0;j<a;j++)
		{
			if(u[j].pos>vp) break;
			if(u[j].pos ==vp) 
			{
				res+=vl*u[j].val;
				break;
			}
		}
	}
	cout<<res;
	return 0;
}

上述代码的时间复杂度是O(n2)的,而a b的最大范围是5* 10 5 ,a*b最大可达2.5 * 1011 ,一秒钟运行2 *107次,极易超时,只能得30分。所以应该将两组数据并到一组里按照位置的大小进行排序,位置相等的前后两个dex的值val相乘加入结果res中,代码:

#include<bits/stdc++.h>
using namespace std;
struct dex
{
	long long pos;
	int val;
};
int cmp(dex a,dex b)
{
	return a.pos <b.pos; 
}
int main()
{
	int n,a,b;
	long long res=0;
	cin>>n>>a>>b;
	dex u[a+b];
	for(int i=0;i<a+b;i++) 
	{
		cin>>u[i].pos >>u[i].val;
	}
	sort(u,u+a+b,cmp);
	for(int i=0;i<a+b-1;i++)
	{
		if(u[i].pos ==u[i+1].pos ) res+=u[i].val *u[i+1].val ;
	}
	cout<<res;
	return 0;
}

此算法的时间复杂度:sort函数O(nlgn),最后一个for循环O(n),a+b的最大值是1*106,不会超时。

12.在这里插入图片描述
注意:一定一定要注意边界位置!比如第一个单词或者最后一个单词,以及最后一个句子!
在这里插入图片描述
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
int main()
{
	char c;
	vector<string>word;
	string med="";
	while(scanf("%c",&c)!=EOF)
	{
		if(c=='\n')//这个句子结束了
		{
			word.push_back(med);//一个句子的最后一个单词一定要加入进来!!
			med="";
			for(int i=word.size()-1;i>=0;i--) cout<<word[i]<<' ';
			cout<<endl;
			word.clear();
		}
		else if(c==' ')//这个单词结束了
		{
			word.push_back(med);
			med="";
		}
		else
		{
			med+=c;
		} 
	}
//一定要考虑最后一个句子是否能够输出,非常有可能最后一个输出的字符不是换行符,这个时候最后一个句子不会进行输出,所以要在最后对最后这个句子进行输出!!!
	word.push_back(med);
	med="";
	for(int i=word.size()-1;i>=0;i--) cout<<word[i]<<' ';
	cout<<endl;
	word.clear();
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值