CCF、CSP历年真题(T1合集)

最初刷题,是按照年份,后来改变策略,由易到难,先做完所有年份的第一题,再做所有年份的第二题,依次类推…
(所有代码已经校验可以获得100分)

代码地址:
https://github.com/hlk-1135/Data-Structures-and-Algorithms/tree/master/CCF

注: T1不难。所以只给了代码以及在部分代码上加了注解,没有写题解。


试题编号: 201812-1
试题名称: 小明上学
问题描述:

  小明是汉东省政法大学附属中学的一名学生,他每天都要骑自行车往返于家和学校。为了能尽可能充足地睡眠,他希望能够预计自己上学所需要的时间。他上学需要经过数段道路,相邻两段道路之间设有至多一盏红绿灯。
  京州市的红绿灯是这样工作的:每盏红绿灯有红、黄、绿三盏灯和一个能够显示倒计时的显示牌。假设红绿灯被设定为红灯 r 秒,黄灯 y 秒,绿灯 g 秒,那么从 0 时刻起,[0,r) 秒内亮红灯,车辆不许通过;[r, r+g) 秒内亮绿灯,车辆允许通过;[r+g, r+g+y) 秒内亮黄灯,车辆不许通过,然后依次循环。倒计时的显示牌上显示的数字 l(l > 0)是指距离下一次信号灯变化的秒数。
问题描述
  一次上学的路上,小明记录下了经过每段路的时间,和各个红绿灯在小明到达路口时的颜色和倒计时秒数。希望你帮忙计算此次小明上学所用的时间。
输入格式
  输入的第一行包含空格分隔的三个正整数 r、y、g,表示红绿灯的设置。这三个数均不超过 106。
  输入的第二行包含一个正整数 n(n ≤ 100),表示小明总共经过的道路段数和看到的红绿灯数目。
  接下来的 n 行,每行包含空格分隔的两个整数 k、t。k=0 表示经过了一段道路,耗时 t 秒,此处 t 不超过 106;k=1、2、3 时,分别表示看到了一个红灯、黄灯、绿灯,且倒计时显示牌上显示的数字是 t,此处 t 分别不会超过 r、y、g。
输出格式
  输出一个数字,表示此次小明上学所用的时间。
样例输入
30 3 30
8
0 10
1 5
0 11
2 2
0 6
0 3
3 10
0 3
样例输出
70
样例说明
  小明先经过第一段道路,用时 10 秒,然后等待 5 秒的红灯,再经过第二段道路,用时 11 秒,然后等待 2 秒的黄灯和 30 秒的红灯,再经过第三段、第四段道路,分别用时6、3秒,然后通过绿灯,再经过最后一段道路,用时 3 秒。共计 10 + 5 + 11 + 2 + 30 + 6 + 3 + 3=70 秒。
评测用例规模与约定
  测试点 1, 2 中不存在任何信号灯。
  测试点 3, 4 中所有的信号灯在被观察时均为绿灯。
  测试点 5, 6 中所有的信号灯在被观察时均为红灯。
  测试点 7, 8 中所有的信号灯在被观察时均为黄灯。
  测试点 9, 10 中将出现各种可能的情况。
代码:

#include
#include
using namespace std;
int main()
{
	int r,y,g,n;
	int i,k,t,total;
	while(~scanf("%d%d%d",&r,&y,&g)) {
		total=0;
		scanf("%d",&n);
		for(i=0;i<n;i++) {
			scanf("%d%d",&k,&t);
			if(k == 0 || k == 1)
				total+=t;
			else if(k==2)
				total+=(t+r); 
		}
		printf("%d\n",total); 
		return 0;
	}
}

试题编号: 201809-1
试题名称: 卖菜
问题描述:

  在一条街上有n个卖菜的商店,按1至n的顺序排成一排,这些商店都卖一种蔬菜。
  第一天,每个商店都自己定了一个价格。店主们希望自己的菜价和其他商店的一致,第二天,每一家商店都会根据他自己和相邻商店的价格调整自己的价格。具体的,每家商店都会将第二天的菜价设置为自己和相邻商店第一天菜价的平均值(用去尾法取整)。
  注意,编号为1的商店只有一个相邻的商店2,编号为n的商店只有一个相邻的商店n-1,其他编号为i的商店有两个相邻的商店i-1和i+1。
  给定第一天各个商店的菜价,请计算第二天每个商店的菜价。
输入格式
  输入的第一行包含一个整数n,表示商店的数量。
  第二行包含n个整数,依次表示每个商店第一天的菜价。
输出格式
  输出一行,包含n个正整数,依次表示每个商店第二天的菜价。
样例输入
8
4 1 3 1 6 5 17 9
样例输出
2 2 1 3 4 9 10 13
数据规模和约定
  对于所有评测用例,2 ≤ n ≤ 1000,第一天每个商店的菜价为不超过10000的正整数。
代码:

#include
#include
int a[10001];
using namespace std;
int main()
{
	int i,n;
	while(~scanf("%d",&n)) {
		for(i=0;i<n;i++) {
			scanf("%d",&a[i]);
		}
		for(i=0;i<n;i++) {
			if(i==0)
				printf("%d ",(a[0]+a[1])/2);
			else if(i==n-1)
				printf("%d\n",(a[i-1]+a[i])/2);
			else
				printf("%d ",(a[i-1]+a[i]+a[i+1])/3);
		}
	} 
	return 0;
} 

试题编号: 201803-1
试题名称: 跳一跳

问题描述:
  近来,跳一跳这款小游戏风靡全国,受到不少玩家的喜爱。
  简化后的跳一跳规则如下:玩家每次从当前方块跳到下一个方块,如果没有跳到下一个方块上则游戏结束。
  如果跳到了方块上,但没有跳到方块的中心则获得1分;跳到方块中心时,若上一次的得分为1分或这是本局游戏的第一次跳跃则此次得分为2分,否则此次得分比上一次得分多两分(即连续跳到方块中心时,总得分将+2,+4,+6,+8…)。
  现在给出一个人跳一跳的全过程,请你求出他本局游戏的得分(按照题目描述的规则)。
输入格式
  输入包含多个数字,用空格分隔,每个数字都是1,2,0之一,1表示此次跳跃跳到了方块上但是没有跳到中心,2表示此次跳跃跳到了方块上并且跳到了方块中心,0表示此次跳跃没有跳到方块上(此时游戏结束)。
输出格式
  输出一个整数,为本局游戏的得分(在本题的规则下)。
样例输入
1 1 2 2 2 1 1 2 2 0
样例输出
22
数据规模和约定
  对于所有评测用例,输入的数字不超过30个,保证0正好出现一次且为最后一个数字。
代码:

#include
#include
using namespace std;
int main()
{
	int n;
	int score=0;
	int count=0;//统计连续的2的个数 
	while(scanf("%d",&n) && n!=0) {
		if(n==1) {
			score++;
			count=0;//跳2中断,count置0 
		}
		else if(n==2){
			count++;
			score+=count*2;
		}	
	}
	printf("%d\n",score);
	return 0;
} 

试题编号: 201712-1
试题名称: 最小差值
问题描述:

  给定n个数,请找出其中相差(差的绝对值)最小的两个数,输出它们的差值的绝对值。
输入格式
  输入第一行包含一个整数n。
  第二行包含n个正整数,相邻整数之间使用一个空格分隔。
输出格式
  输出一个整数,表示答案。
样例输入
5
1 5 4 8 20
样例输出
1
样例说明
  相差最小的两个数是5和4,它们之间的差值是1。
样例输入
5
9 3 6 1 3
样例输出
0
样例说明
  有两个相同的数3,它们之间的差值是0.
数据规模和约定
  对于所有评测用例,2 ≤ n ≤ 1000,每个给定的整数都是不超过10000的正整数。
代码:

#include
#include
#include
using namespace std;
int a[10001]; 
int main()
{
	int i,j;
	int n,mutex;
	while(~scanf("%d",&n)) {
		for(i=0;i<n;i++) {
			scanf("%d",&a[i]);
		}
		int min=abs(a[0]-a[1]);
		for(i=0;i<n;i++) {
			for(j=i+1;j<n;j++) {
				mutex=abs(a[i]-a[j]);	
				if(mutex<min)
					min=mutex;
			}
		}
		printf("%d\n",min);
	}
	return 0;
} 

试题编号: 201709-1
试题名称: 打酱油
问题描述:

  小明带着N元钱去买酱油。酱油10块钱一瓶,商家进行促销,每买3瓶送1瓶,或者每买5瓶送2瓶。请问小明最多可以得到多少瓶酱油。
输入格式
  输入的第一行包含一个整数N,表示小明可用于买酱油的钱数。N是10的整数倍,N不超过300。
输出格式
  输出一个整数,表示小明最多可以得到多少瓶酱油。
样例输入
40
样例输出
5
样例说明
  把40元分成30元和10元,分别买3瓶和1瓶,其中3瓶送1瓶,共得到5瓶。
样例输入
80
样例输出
11
样例说明
  把80元分成30元和50元,分别买3瓶和5瓶,其中3瓶送1瓶,5瓶送2瓶,共得到11瓶。
代码:

#include
#include
using namespace std;
int main()
{
	int n;
	int i,j,k;
	int num;
	while(~scanf("%d",&n)) {
		i=n/50;
		j=(n-50*i)/30;
		k=(n-50*i-30*j)/10;
		num=7*i+4*j+k;
		printf("%d\n",num);
	} 
	return 0;
} 

试题编号: 201703-1
试题名称: 分蛋糕
问题描述:
  小明今天生日,他有n块蛋糕要分给朋友们吃,这n块蛋糕(编号为1到n)的重量分别为a1, a2, …, an。小明想分给每个朋友至少重量为k的蛋糕。小明的朋友们已经排好队准备领蛋糕,对于每个朋友,小明总是先将自己手中编号最小的蛋糕分给他,当这个朋友所分得蛋糕的重量不到k时,再继续将剩下的蛋糕中编号最小的给他,直到小明的蛋糕分完或者这个朋友分到的蛋糕的总重量大于等于k。
  请问当小明的蛋糕分完时,总共有多少个朋友分到了蛋糕。
输入格式
  输入的第一行包含了两个整数n, k,意义如上所述。
  第二行包含n个正整数,依次表示a1, a2, …, an。
输出格式
  输出一个整数,表示有多少个朋友分到了蛋糕。
样例输入
6 9
2 6 5 6 3 5
样例输出
3
样例说明
  第一个朋友分到了前3块蛋糕,第二个朋友分到了第4、5块蛋糕,第三个朋友分到了最后一块蛋糕。
评测用例规模与约定
  对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ k ≤ 10000,1 ≤ ai ≤ 1000。
代码:

#include
#include
int a[1001];
using namespace std;
int main()
{
	int n,k;
	int i,sum,num;
	while(~scanf("%d%d",&n,&k)) {
		sum=num=0;
		for(i=0;i<n;i++) {
			scanf("%d",&a[i]);
		}
		for(i=0;i<n;i++) {
			sum+=a[i];
			if(sum>=k) {
				num++;
				sum=0;
			}
		}
		//若sum=0,说明蛋糕正好分完;sum>0,说明还剩余蛋糕,则分给最后一个朋友
		if(sum>0) 
			num++;
		printf("%d\n",num);
	}
	return 0;
}

试题编号: 201612-1
试题名称: 中间数
问题描述:

  在一个整数序列a1, a2, …, an中,如果存在某个数,大于它的整数数量等于小于它的整数数量,则称其为中间数。在一个序列中,可能存在多个下标不相同的中间数,这些中间数的值是相同的。
  给定一个整数序列,请找出这个整数序列的中间数的值。
输入格式
  输入的第一行包含了一个整数n,表示整数序列中数的个数。
  第二行包含n个正整数,依次表示a1, a2, …, an。
输出格式
  如果约定序列的中间数存在,则输出中间数的值,否则输出-1表示不存在中间数。
样例输入
6
2 6 5 6 3 5
样例输出
5
样例说明
  比5小的数有2个,比5大的数也有2个。
样例输入
4
3 4 6 7
样例输出
-1
样例说明
  在序列中的4个数都不满足中间数的定义。
样例输入
5
3 4 6 6 7
样例输出
-1
样例说明
  在序列中的5个数都不满足中间数的定义。
评测用例规模与约定
  对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ ai ≤ 1000。
代码:

#include
#include
#include
int a[1001];
using namespace std;
int main()
{
	int i,j,k,n;
	int num1,num2;
	while(~scanf("%d",&n)) {
		for(i=0;i<n;i++) {
			scanf("%d",&a[i]);
		}
		sort(a,a+n);
		bool flag=false;
		for(i=0;i<n;i++) {
			num1=num2=0;
			for(j=0;j<i;j++) {
				if(a[j]<a[i])
					num1++;
			}
			for(k=i+1;k<n;k++) {
				if(a[k]>a[i])
					num2++;	
			}
			if(num1 == num2) {
				flag=true;
				printf("%d\n",a[i]);
				break;
			}
		}
		if(!flag)
			printf("-1\n");
	}
	return 0;
}

试题编号: 201609-1
试题名称: 最大波动
问题描述:

  小明正在利用股票的波动程度来研究股票。小明拿到了一只股票每天收盘时的价格,他想知道,这只股票连续几天的最大波动值是多少,即在这几天中某天收盘价格与前一天收盘价格之差的绝对值最大是多少。
输入格式
  输入的第一行包含了一个整数n,表示小明拿到的收盘价格的连续天数。
  第二行包含n个正整数,依次表示每天的收盘价格。
输出格式
  输出一个整数,表示这只股票这n天中的最大波动值。
样例输入
6
2 5 5 7 3 5
样例输出
4
样例说明
  第四天和第五天之间的波动最大,波动值为|3-7|=4。
评测用例规模与约定
  对于所有评测用例,2 ≤ n ≤ 1000。股票每一天的价格为1到10000之间的整数。
代码:

#include
#include
#include
using namespace std;
int a[1001];
int main()
{
	int i,n;
	int max=0;
	while(~scanf("%d",&n)) {
		for(i=0;i<n;i++) {
			scanf("%d",&a[i]);
		}
		for(i=1;i<n;i++) {
			int v=abs(a[i]-a[i-1]);
			if(v>max)
				max=v;
		}
		printf("%d\n",max);
	}
	return 0;
}

试题编号: 201604-1
试题名称: 折点计数
问题描述:

  给定n个整数表示一个商店连续n天的销售量。如果某天之前销售量在增长,而后一天销售量减少,则称这一天为折点,反过来如果之前销售量减少而后一天销售量增长,也称这一天为折点。其他的天都不是折点。如下图中,第3天和第6天是折点。
CCF、CSP历年真题(T1合集)_第1张图片
  给定n个整数a1, a2, …, an表示销售量,请计算出这些天总共有多少个折点。
  为了减少歧义,我们给定的数据保证:在这n天中相邻两天的销售量总是不同的,即ai-1≠ai。注意,如果两天不相邻,销售量可能相同。
输入格式
  输入的第一行包含一个整数n。
  第二行包含n个整数,用空格分隔,分别表示a1, a2, …, an。
输出格式
  输出一个整数,表示折点出现的数量。
样例输入
7
5 4 1 2 3 6 4
样例输出
2
评测用例规模与约定
  所有评测用例满足:1 ≤ n ≤ 1000,每天的销售量是不超过10000的非负整数。
代码:

#include
#include
using namespace std;
int a[1001];
int main()
{
	int i,n;
	int count;
	while(~scanf("%d",&n)) {
		count=0;
		for(i=0;i<n;i++)
			scanf("%d",&a[i]);
		for(i=1;i<n-1;i++) {
			if(((a[i]-a[i-1])>0 && (a[i]-a[i+1])>0) || 
			((a[i]-a[i-1])<0 && (a[i]-a[i+1])<0))
				count++;
		}
		printf("%d\n",count);
	}
	return 0;
}

试题编号: 201512-1
试题名称: 数位之和
问题描述:

  给定一个十进制整数n,输出n的各位数字之和。
输入格式
  输入一个整数n。
输出格式
  输出一个整数,表示答案。
样例输入
20151220
样例输出
13
样例说明
  20151220的各位数字之和为2+0+1+5+1+2+2+0=13。
评测用例规模与约定
  所有评测用例满足:0 ≤ n ≤ 1000000000。
代码:

#include
#include
using namespace std;
int main()
{
	int n;
	int sum;
	while(~scanf("%d",&n)) {
		sum=0;
		while(n) {
			sum+=n%10;
			n/=10;
		}
		printf("%d\n",sum);
	}
	return 0;
}

试题编号: 201509-1
试题名称: 数列分段
问题描述:

  给定一个整数数列,数列中连续相同的最长整数序列算成一段,问数列中共有多少段?
输入格式
  输入的第一行包含一个整数n,表示数列中整数的个数。
  第二行包含n个整数a1, a2, …, an,表示给定的数列,相邻的整数之间用一个空格分隔。
输出格式
  输出一个整数,表示给定的数列有多个段。
样例输入
8
8 8 8 0 12 12 8 0
样例输出
5
样例说明
  8 8 8是第一段,0是第二段,12 12是第三段,倒数第二个整数8是第四段,最后一个0是第五段。
评测用例规模与约定
  1 ≤ n ≤ 1000,0 ≤ ai ≤ 1000。
代码:

#include
#include
int a[1001];
int main()
{
	int i,n;
	int count;
	while(~scanf("%d",&n)) {
		count=1;
		for(i=0;i<n;i++) {
			scanf("%d",&a[i]);
		}
		for(i=1;i<n;i++) {
			if(a[i]!=a[i-1])
				count++;
		}
		printf("%d\n",count);
	}
	return 0;
}

试题编号: 201503-1
试题名称: 图像旋转
问题描述:

  旋转是图像处理的基本操作,在这个问题中,你需要将一个图像逆时针旋转90度。
  计算机中的图像表示可以用一个矩阵来表示,为了旋转一个图像,只需要将对应的矩阵旋转即可。
输入格式
  输入的第一行包含两个整数n, m,分别表示图像矩阵的行数和列数。
  接下来n行每行包含m个整数,表示输入的图像。
输出格式
  输出m行,每行包含n个整数,表示原始矩阵逆时针旋转90度后的矩阵。
样例输入
2 3
1 5 3
3 2 4
样例输出
3 4
5 2
1 3
评测用例规模与约定
  1 ≤ n, m ≤ 1,000,矩阵中的数都是不超过1000的非负整数。
代码:

#include
#include
using namespace std;
int a[1001][1001];
int main()
{
	int m,n,i,j;
	while(~scanf("%d%d",&n,&m)) {
		for(i=0;i<n;i++) {
			for(j=0;j<m;j++) {
				scanf("%d",&a[i][j]);
			}
		}
		for(i=m-1;i>=0;i--) {
			for(j=0;j<n;j++) {
				if(j==n-1)
					printf("%d\n",a[j][i]);
				else
					printf("%d ",a[j][i]);
			}
		}
	}
	return 0;
}

试题编号: 201412-1
试题名称: 门禁系统
问题描述:

  涛涛最近要负责图书馆的管理工作,需要记录下每天读者的到访情况。每位读者有一个编号,每条记录用读者的编号来表示。给出读者的来访记录,请问每一条记录中的读者是第几次出现。
输入格式
  输入的第一行包含一个整数n,表示涛涛的记录条数。
  第二行包含n个整数,依次表示涛涛的记录中每位读者的编号。
输出格式
  输出一行,包含n个整数,由空格分隔,依次表示每条记录中的读者编号是第几次出现。
样例输入
5
1 2 1 1 3
样例输出
1 1 2 3 1
评测用例规模与约定
  1≤n≤1,000,读者的编号为不超过n的正整数。
代码:

#include
#include
#include
int a[1001];
int b[1001];
int main()
{
	int i,n;
	while(~scanf("%d",&n)) {
		for(i=1;i<=n;i++) {
			scanf("%d",&a[i]);
		}
		for(i=1;i<=1001;i++) {
			b[i]=1; 
		}
		for(i=1;i<=n;i++){
			if(i==n) {
				printf("%d\n",b[a[i]]);
				b[a[i]]++;
			}
			else {
				printf("%d ",b[a[i]]);
				b[a[i]]++;
			}
				
		}
	}
	return 0;
}

试题编号: 201409-1
试题名称: 相邻数对
问题描述:

  给定n个不同的整数,问这些数中有多少对整数,它们的值正好相差1。
输入格式
  输入的第一行包含一个整数n,表示给定整数的个数。
  第二行包含所给定的n个整数。
输出格式
  输出一个整数,表示值正好相差1的数对的个数。
样例输入
6
10 2 6 3 7 8
样例输出
3
样例说明
  值正好相差1的数对包括(2, 3), (6, 7), (7, 8)。
评测用例规模与约定
  1<=n<=1000,给定的整数为不超过10000的非负整数。
代码:

#include
#include
#include
using namespace std;
int a[1001];
int main()
{
	int i,j,n;
	int num;
	while(~scanf("%d",&n)) {
		num=0;
		for(i=0;i<n;i++) {
			scanf("%d",&a[i]);
		}
		for(i=0;i<n;i++) {
			for(j=i+1;j<n;j++) {
				if(abs(a[i]-a[j])==1)
					num++;
			}
		}
		printf("%d\n",num);
	}
	return 0;
} 

试题编号: 201403-1
试题名称: 相反数
问题描述:

  有 N 个非零且各不相同的整数。请你编一个程序求出它们中有多少对相反数(a 和 -a 为一对相反数)。
输入格式
  第一行包含一个正整数 N。(1 ≤ N ≤ 500)。
  第二行为 N 个用单个空格隔开的非零整数,每个数的绝对值不超过1000,保证这些整数各不相同。
输出格式
  只输出一个整数,即这 N 个数中包含多少对相反数。
样例输入
5
1 2 3 -1 -2
样例输出
2
代码:

#include
#include
#include
using namespace std;
int a[501];
int main()
{
	int n;
	int i,j,num;
	while(~scanf("%d",&n)) {
		num=0;
		for(i=0;i<n;i++) {
			scanf("%d",&a[i]);
		}
		for(i=0;i<n;i++) {
			for(j=i+1;j<n;j++) {
				if(abs(a[i]) == abs(a[j]))
					num++;
			}
		}
		printf("%d\n",num);
	}
	return 0;
}

试题编号: 201312-1
试题名称: 出现次数最多的数
问题描述:

  给定n个正整数,找出它们中出现次数最多的数。如果这样的数有多个,请输出其中最小的一个。
输入格式
  输入的第一行只有一个正整数n(1 ≤ n ≤ 1000),表示数字的个数。
  输入的第二行有n个整数s1, s2, …, sn (1 ≤ si ≤ 10000, 1 ≤ i ≤ n)。相邻的数用空格分隔。
输出格式
  输出这n个次数中出现次数最多的数。如果这样的数有多个,输出其中最小的一个。
样例输入
6
10 1 10 20 30 20
样例输出
10
代码(方法一):

#include
#include
#include
using namespace std;
int a[10001];
int main()
{
	int i,n,num,sum;
	int count=0;
	int max=0;
	while(~scanf("%d",&n)) {
		memset(a,0,10001);
		for(i=1;i<=n;i++) {
			scanf("%d",&num);
			a[num]++;
			if(num>max)
				max=num;
		}
		for(i=1;i<=max;i++) {
			if(a[i]!=0 && a[i]>count) {
				count=a[i];
				sum=i;
			}
		}
		printf("%d\n",sum);
	}
	return 0;
} 

代码(方法二):

#include
#include
using namespace std;
int a[10001];

int main()
{
	int i,j,n;
	while(~scanf("%d",&n)) {
		for(i=0;i<n;i++) {
			scanf("%d",&a[i]);
		}
		
		int max=0;
		int num=a[0];
		for(i=0;i<n;i++) {
			int sum=0;
			for(j=0;j<n;j++) {
				if(a[j]==a[i])
					sum++;
			}
			if(sum>max) {
				max=sum;
				num=a[i];
			} else if(sum==max && a[i]<num) {
				max=sum;
				num=a[i];
			}
					
		}
		printf("%d\n",num);
	}
	return 0;
} 

你可能感兴趣的:(C/C++,算法分析与设计)