2019 上海小学组 题目解析

2019年上海市青少年算法竞赛(小学组) 解析版

 

时间:2019111714:3017:00

 

题目名

数列

烦恼

停车计费

小区评比

贪婪的国王

等边三角形

子目录

shulie

fannao

tcjf

xqpb

tlgw

dbsjx

源程序

文件名

shulie.c

shulie.cpp

fannao.c

fannao.cpp

tcjf.c

tcjf.cpp

xqpb.c

xqpb.cpp

tlgw.c

tlgw.cpp

dbsjx.c

dbsjx.cpp

输入

文件名

shulie.in

fannao.in

tcjf.in

xqpb.in

tlgw.in

dbsjx.in

输出

文件名

shulie.out

fannao.out

tcjf.out

xqpb.out

tlgw.out

dbsjx.out

测试点

数量

20

20

20

20

20

20

单点

时限

2秒

2秒

2秒

2秒

2秒

2秒

内存

限制

256M字节

256M字节

256M字节

256M字节

256M字节

256M字节

 

说明:

1. 请将D盘中“小学”文件夹改名为“准考证”加“选手姓名拼音”文件夹。

例如,假设选手的准考证号为SH-1234,姓名拼音为tuling,则文件夹的名字应改成

SH-1234tuling。

2. 输入输出都需要使用文本文件,文件名如上所示。

 

 

 

第一题 数列

描述

  联欢会上,主持人先在黑板上写了四个数字,分别是:2,0,1,9,然后说:“这串数字从第五个数起,每一个数都是它前四数字之和的个位数字”。请你打印输出这个数列的前N项,并计算前N项的和。

输入格式

  单个整数:表示项数N

输出格式

  第一行:N个数字,表示所求数列的前N项。

  第二行:单个数字,表示前N项数字的和。

数据范围

  1≤N≤100000

样例

输入

输出

10

2 0 1 9 2 2 4 7 5 8

40

点评:今年小学组的第一题出的有点难了,让很多来签到的同学都变成了0分。正常来说输入输出加个判定就差不多了,今年的第一题考察点考查了数组、循环和判定。

那下面看一下我的参考代码吧,里面有相应的注释,OMG,看它,看它!

#include<bits/stdc++.h>
using namespace std;
int main(){
//	freopen("shulie.in","r",stdin);
//	freopen("shulie.out","w",stdin);
	int n,sum=12,t=12,k=0,a[10000]={2,0,1,9};
	cin>>n;
	for(int i=0;i<4;i++) 
		cout<<a[i]<<" ";
	for(int i=4;i<n;i++){
		a[i]=t%10;//取出和的个位数 
		cout<<a[i]<<" ";
		sum+=a[i];//总和 
		t-=a[k];//当前四位数,减掉前一位,加上新的一位 
		t+=a[i];		
		k++;
	}
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

 

 

第二题 烦恼

描述

  老师每天都要批改作文,他想知道这篇作文有多少字符,以及多少单词,请你帮助他。

输入格式

  单独一行字符串:表示作文的内容,保证只出现大小写英文字母、数字或空格。

输出格式

  第一行:单个整数,表示输入字符串中的可见字符的个数。英文字母和数字属于可见字符,空格和换行属于不可见字符。

  第二行:单个整数,表示输入字符串中的单词个数。单词是指连续的,由可见字符组成的字符串。

数据范围

  设输入字符串长为|s|,保证1≤|s|≤100000,两个相邻的单词间有且仅有一个空格。

样例

输入

输出

One apple a day

12

4

 

输入

输出

7 days a week

10

4

 

点评:本题考查了两个知识点,一个是字符类型的判定,一个是单词个数的计算,其中单词个数的计算在以前的考试中有考到,并且今年的题目明确的说了两个单词间仅有一个空格,因此我们都可以直接遍历数组,找到空格个数+1就可以了。

那下面看一下我的参考代码吧,里面有相应的注释,OMG,看它,看它!

#include<bits/stdc++.h>
using namespace std;
int main(){
//	freopen("fannao.in","r",stdin);
//	freopen("fannao.out","w",stdin);
	int k=0,w=1;
	string s;
	getline(cin,s);
	int l=s.length();//求字符串的长度 
	for(int i=0;i<l;i++){
		//记录单词个数
		if((s[i]>='0'&&s[i]<='9')||(s[i]>='a'&&s[i]<='z')||(s[i]>='A'&&s[i]<='Z')){
			//字母 数字
			k++;
		} 	
		// 单词 
		else if(s[i]==' '){
			w++;
		}
	}
	cout<<k<<endl<<w<<endl;
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

 

 

第三题 停车计费

描述

  某小区对外来车辆按照如下规则计费:

  1. 半小时内(含半小时),免费;
  2. 超过半小时到六小时(含六小时),每小时2元,不足一小时以一小时计算;
  3. 超过六小时,每小时5元,不足一小时以一小时计算。

  给定车辆的进入和离开时间(保证没有跨过一天的零点),请计算应收金额。

输入格式

  第一行:一个字符串,表示车辆进入小区的时间。

  第二行:一个字符串,表示车辆离开小区的时间。

  输入采用“HH:MM:SS”的形式表示时间,其中“HH”表示小时,范围为00到23,“MM”表示分钟,范围为00到59,“SS”描述秒数,范围为00到59。时、分、秒均为两位数。

输出格式

  第一行:表示车辆的停留时间,格式与输入保持相同。

  第二行:单个整数,表示停车费用。

样例

输入

输出

10:00:00

14:00:00

04:00:00

8

 

输入

输出

12:34:56

20:36:22

08:01:26

45

 

输入

输出

23:29:59

23:59:59

00:30:00

0

点评:这道题可以有两种做法,一个是用定义整型、字符型、整型、字符型、整型来接受数据,另外一种就是常规操作,读入字符串中,然后遍历。在这里我们要提一下用scanf来处理就很方便了,在代码中我没有写,在这里简单的说一下,scanf("%d:%d:%d",&h,&m,&s);这就可以直接存放了数据了,还不会引起bug。

那下面看一下我的参考代码吧,里面有相应的注释,OMG,看它,看它!

#include<bits/stdc++.h>
using namespace std;
int main() {
//	freopen("tcjh.in","r",stdin);
//	freopen("tcjh.out","w",stdin);
	int h1,m1,s1,h2,m2,s2,h,m,s;
	char a;
	//两种做法,我们用一种比较取巧的做法(这是跟我的学生学会的
	//另外一种做法就是定义字符串,输入字符串,遍历,然后转换成数字再比较 
	cin>>h1>>a>>m1>>a>>s1;// 因为是定长和内容是固定的,因此可以用对应的变量来存放数据 
	cin>>h2>>a>>m2>>a>>s2;
	h=h2-h1;//分别计算 小时差 分钟差 秒差 
	m=m2-m1;
	s=s2-s1;
	if(s<0) {//从小到大借位 
		m--;
		s+=60;
	}
	if(m<0) {
		m+=60;
		h--;
	}
	
	//若小于10的数字,我们需要补0,或者输出h/10 h%10 也能解决这个问题 
	if(h<10)
		cout<<0;	
	cout<<h<<":";
	if(m<10)
		cout<<0;
	cout<<m<<":";
	if(s<10)
		cout<<0;
	cout<<s<<endl;
	
	//输出时间后,判定付费情况,分段处理 
	if(h==0) {//h==0 则考虑免费问题 
		if((m<=30&&s==0)||m<30) {
			cout<<0;
		}
	} else if(h<6) {//小于6小时时,则正常计费 
		if(m>0||s>0) {
			cout<<(h+1)*2;
		}else{
			cout<<h*2;
		}
	} else if(h==6&&m==0&&s==0) {//等于6小时时 特判 
		cout<<12;
	}else{//超过的情况 
		if(m>0||s>0) {
			cout<<(h+1)*5;
		}else{
			cout<<h*5;
		} 
	}
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

第四题 小区评比

描述

  某城市有16个小区,这些小区分别用大写的英文字母A到P编号。为创建文明城市,工作人员对一些小区进行了检查,并且评出了分数,评分结果可以用以下字符串表示:

分数1小区编号1分数2小区编号2分数3小区编号3⋯⋯分数n小区编号n#

  这串字符串的格式说明如下:

  1. 每个分数都是1到100之间的整数,也包括1和100;
  2. 每个小区编号都是大写英文字母A到P中的一个,保证没有重复的编号出现;
  3. 最后一个结束字符为#,表示记录终止。

  请你读入数据后统计并分析,输出分数最高和最低的小区编号。

输入格式

  第一行:一个字符串,表示各个小区的分数分布。

输出格式

  第一个字母:表示得分最高的小区编号,如果有多个小区并列最高,只输出字母顺序中最靠前的编号。

  第二个字母:表示得分最低的小区编号,如果有多个小区并列最低,只输出字母顺序中最靠前的编号。

样例

输入

输出

85K98B87D80F92H78C96A#

BC

解释:A小区96分,B小区98分,C小区78分,D小区87分,F小区80分,H小区92分,K小区85分。最高分是B小区,最低分是C小区。

点评:后面几道题开始都是历年原题了。本题是和学生分数是一样的题,出题人有点偷懒了,因为本题需要记录一些信息,然后再拆分,并且不知道具体的长度和内容,因此不能用我们上面说的那种偷懒的方法了,我们就直接输入字符串,然后遍历,以#号结束。下面我提供了两种做法,一种是利用结构体存放数据,然后利用sort函数排序,最后取第一个和最后一个值就是他们的最大最小值了;另外一种做法是利用打擂台的思想去做的,本题只需要最大和最小值,因此只需要开几个变量来存放对应的值即可。

那下面看一下我的参考代码吧,里面有相应的注释,OMG,看它,看它!

做法一:

#include<bits/stdc++.h>
using namespace std;
struct bs{
	int t;
	char b;
};
bool cmp(bs a,bs c){
	if(a.t>c.t){
		return 1;
	}
	else if(a.t==c.t){
		return a.b<c.b;
	}
	else return 0;
}
int main(){
//	freopen("","r",stdin);
//	freopen("","w",stdin);

	bs a[10000];
	int t=0,k=0;
	string s;
	cin>>s;
	int l=s.length();
	cout<<l<<endl; 
	for(int i=0;s[i]!='#';i++){//我们的结束条件是#结束 
		if(s[i]>='0'&&s[i]<='9'){
			//将字符转换成数字的常规操作,因为不能它是几位数,因此可以这样去转换 
			//和取逆序数是一样的道理 
			t=t*10+s[i]-'0';
		}else{//遇到字符就是小区编号,存放成绩和小区编号 
			a[k].t=t;
			a[k].b=s[i];
			t=0;
			k++;
		}
	}

	sort(a,a+k,cmp);//进行排序,从大到小 
//	for(int i=0;i<k;i++){
//		cout<<a[i].t<<" "<<a[i].b<<endl; 
//	}
	cout<<a[0].b<<a[k-1].b;//输出第一个和最后一个 
	
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

 

做法二:

#include<bits/stdc++.h>
using namespace std;

int main(){
//	freopen("","r",stdin);
//	freopen("","w",stdin);


	int t=0,k=0,maxx=0,minn=0x7fffffff;
	char maxc,minc;
	string s;
	cin>>s;
	int l=s.length();
//	cout<<l<<endl; 

	for(int i=0;s[i]!='#';i++){//我们的结束条件是#结束 
		if(s[i]>='0'&&s[i]<='9'){
			//将字符转换成数字的常规操作,因为不能它是几位数,因此可以这样去转换 
			//和取逆序数是一样的道理 
			t=t*10+s[i]-'0';
		}else{//遇到字符就是小区编号,存放成绩和小区编号 
			//打擂台做法,只需要存最大和最小即可 
			if(maxx<t){
				maxx=t;
				maxc=s[i];
			} else if(maxx==t){
				if(maxc>s[i]){
					maxc=s[i];
				}
			}
			if(minn>t){
				minn=t;
				minc=s[i];
			}else if(minn==t){
				minc=s[i];
			}
			t=0;
		}
	}
	cout<<maxc<<minc;

	
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

 

第五题 贪婪的国王

描述

  有个国王喜欢不断积累金币,有一天,他向国民宣布了新的征收办法:

  1. 第一天,国民要向国王缴纳一枚金币;
  2. 第二天和第三天,国民每天要向国王缴纳两枚金币;
  3. 在之后的三天,也就是第四、第五、第六天,国民每天要向国王缴纳三枚金币;
  4. 在之后连续四天,也就是第七、八、九、十天,每天缴纳四枚金币;

  总结来说,当国民连续n天每天缴纳了n枚金币之后,国王要求在接下来的n+1天里每天缴纳n+1枚金币。

  国王有个目标数量T,请问需要征收多少天金币,才能让国王的金币数量大于或等于T

输入格式

  单个整数:表示征收金币的目标数量T

输出格式

  单个整数:表示达到目标数量的天数。

数据范围

  1≤T≤100000000

样例

输入

输出

14

6

解释:每天征收的金币数量分别为1+2+2+3+3+3=14

 

输入

输出

29822

1001

点评:本题和骑士的金币一样的题目,需要注意的点是超过的部分注意是最近的那个点,而不是最后的点。

那下面看一下我的参考代码吧,里面有相应的注释,OMG,看它,看它!

#include<bits/stdc++.h>
using namespace std;
int main(){
//	freopen("","r",stdin);
//	freopen("","w",stdin);

	int sum=0,t,m=1,d=0,k,f=0;
	cin>>t;
	while(sum<t){
		
		f=0;
		for(int i=1;i<=m;i++){
			sum+=m;
			d++;
			if(sum>=t) {
				f=1;
				break;
			}
		}
		m++;
		if(f)  break;
	}
	cout<<d<<endl;
	
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}


 

第六题 等边三角形

描述


  将一个等边三角形的三条边分别N等分,沿着三条边的方向做这些等分点的平行线,就得到了一个三角网格。例如N=6时的网格如图所示:

 

 

  这个网络中有很多三角形。请求出有多少不同的三角形,并且求出这些不同三角形的面积之和。

  两个三角形如果大小不同,或方向不同,或位置不同,则视作两个不同的三角形。在求面积的时候,视网格中最小的三角形面积为1

输入格式

  单个整数:表示N

输出格式

  第一行,单个整数:表示不同三角形的数量。

  第二行,单个整数:表示不同三角形的面积总和。

数据范围

  2≤n≤500

样例

输入

输出

4

 

27

87

 

点评:本题一字未改!本题考查的点是找到对应的规律,然后用代码实现即可,这里我们参考一个数学的解析https://blog.csdn.net/qq_34706280/article/details/53364237,本题参考代码没有解析,希望同学们看完之后,自己能在上面写出对应的解析,以达到学习的作用。

那下面看一下我的参考代码吧,里面有相应的注释,OMG,看它,看它!

#include<bits/stdc++.h>
using namespace std;
int main() {
	//freopen("","r",stdin);
	//freopen("","w",stdout);
	int n,sum=0,num=0;
	int s[500]= {0};
	cin>>n;
	for(int i=1; i<=n; i++) {
		s[i]=pow(i,2);
	}
	for(int j=1; j<=n; j++) {
		for(int k=1; k<=n-j+1; k++) {
			sum+=k*s[j];
			num+=k;
		}
		for(int y=1; y<=n-2*j+1; y++) {
			sum+=y*s[j];
			num+=y;
		}
	}
	cout<<num<<endl;
	cout<<sum<<endl;
	return 0;
}

最后总结,今年的题目适合给普及组做为练手题去做,为一些基础知识加强训练,保证普及组一二题能全对!加油,小学组仅仅是一个起步阶段,未来还有很精彩的世界等你去发现。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值