2022 年合肥市经开区第七届青少年信息学竞赛 小学组试题题解

目录

第一题 车辆统计

第二题 直角三角形

第三题 质因数

第四题 采摘苹果


第一题 车辆统计

(car.cpp)
       国豪家的小区旁边有个 T 字型的路口。暑假的时候,国豪会坐到路口旁边的树荫下纳凉。有时候,他一遍纳凉,一遍会观察从路口驶过的汽车,他发现大部分司机都严格遵守交通规则,在绿灯的时候通过路口,还有一些司机会抢着黄灯冲过路口,这样做其实挺危险,更有甚者,有少部分司机会无视红灯的存在,直接闯红灯通过路口,看得国豪心惊肉跳。现在给出某段时间国豪观察的车辆通过情况,请你统计绿灯、黄灯、红灯三种情况下通过的车辆数。
输入:
由 green、yellow、red 三个单词构成的字符串,分别表示一辆车在
绿色、黄色、红色的交通灯下经过路口。
输出:
一行三个整数,表示绿灯、黄灯、红灯三种情况下通过的车辆数。
样例输入:
greengreenyellowgreenredgreenyellow
样例输出:
4 2 1
说明:
整个字符串有 4 个 green,2 个 yellow 和 1 个 red,说明有 4 辆车在
绿灯的情况下通过,有 2 辆车在黄灯的情况下通过,有 1 辆车在红灯
的情况下通过。
数据范围:
3<=字符串的长度<=10000
题解:
       本题主要考察字符串相关知识,因为green、yellow、red这3个字符串中,都有各自特有的字符,例如:green中的'g'和'n'、yellow中的’y‘、'l'、'w'、red中的'd',也就是说,输入的字符串中,只要出现了一个'g',就出现了一次"green",yellow和red同理。因此,我们只需要统计特殊字符出现的次数,分别用3个变量来计数,即可解出本题。
参考程序:
#include 
#include 
using namespace std;

string s;
int green=0,yellow=0,red=0;

int main(){
	//freopen("car.in","r",stdin);
	//freopen("car.out","w",stdout);
	
	cin>>s;
	for(int i=0;i

第二题 直角三角形

(rt.cpp)
        国豪和国庆很喜欢数学,他们很早就自学了三角形的相关知识。三角形的三边长分别用 a、b、c 三个字母表示,如果这三边的边长满足如下关系:a^2 +b^ 2 =c^ 2 ,则说明它们构成了一个直角三角形,且 a 和 b为直角边,c 为斜边。现给出 n 条边的边长,请你从中选出三条边,让它们能构成一个直角三角形,请问一共能构成多少个直角三角形。
输入:
共两行。第一行,一个整数 n,表示有 n 条边。第二行 n 个正整数,
表示每条边的长度。
输出:
共一行,一个整数,表示能构成的直角三角形的个数。
样例输入:
7
4 3 4 1 3 5 4
样例输出:
6
说明:
a^ 2 读 a 的平方,表示有 2 个 a 相乘,即 a×a。
对于样例输入,可以从 7 条边中选出边长为 3、4、5 的三条边,因为 3^ 2 +4^ 2 =5^ 2 ,所以这三条边能构成一个直角三角形,又因为 3 出现了 2
次,4 出现了 3 次,所以一共能构成 2*3=6 个直角三角形。
数据范围:
3<=n<=100000
1<=每条边的长度<=1000
题解:
        本题主要是从一组数字中,找出能够构成直角三角形的组合数,而且这些数字中可能出现重复数字。既然是查找组合数(3个数),那么我们第一思想肯定是用循环来遍历,找出所有可能的3个数的组合,一一去判断这3个数能否构成直角三角形(也就是a^2+b^2==c^2)。这种思想是可以的,按照这种思路,我们需要用到三重for循环,而这样会使代码的效率变得很低,当测试数据量比较大的时候,可能会出现超时甚至运行不出结果的情况。因此,我们得想办法对这种思路进行一个改进。
        首先,数组中可能会存在重复数字,我们可以使用map打表计数。或者简单一点,构造一个二维数组,第一列用来记录数值,第二列用来记录这个数值出现的次数(这个原理和map是一样的)。我们在找到可以构成直角三角形的组合数时,就可以直接将对应的第二列的数相乘,然后累加,得出的就是构成的三角形个数。这样就解决了重复数字的问题,优化了代码效率。
        其次,还需要对循环进行改进。既然三重for循环超时,我们可以试试化三重为二重。也就是说,遍历组合数的时候,我们只遍历其中两个数,然后将这两个数作为直角边,计算出以这两个数作为直角边对应的斜边,最后在数组中查找存不存在这条斜边,如果存在,说明这3个数可以构成直角三角形,接着就可以将这3个数的次数(二维数组第二列)相乘,然后累加在计数器中;如果不存在,就不做处理。
        最后,对于上面提到的查找,可以采用二分查找提高效率。这里没学过二分查找的可以自己去补充一下这部分的知识。先对数据进行排序,再利用二分查找,可以大大提高代码的效率。
参考程序:
#include 
#include 
using namespace std;

int n,a[100005],cnt=0,i,j,k,result=-1,target;
int num[100005][2];
int c[100005]={0};
int index=0;

//二分查找斜边 
int BinarySearch(int arr[][2], int j,int len, int target) {
	int low = j+1;
	int high = len;
	int mid = 0;
	while (low <= high) {
		mid = (low + high) / 2;
		if (target < arr[mid][0]*arr[mid][0]) high = mid - 1;
		else if (target > arr[mid][0]*arr[mid][0]) low = mid + 1;
		else return mid;
	}
	return -1;
}

int main(){
	//freopen("rt.in","r",stdin);
	//freopen("rt.out","w",stdout);
	
	cin>>n;
	for(i=0;i>a[i];
	
	//次数累乘法:建立一个二维数组,第一列为数的数值,第二列为该数值出现的次数
	//首先统计每个元素出现的次数	
	for(i=0;i

第三题 质因数

(prime.cpp)
        国豪知道素数的多种判定方法,比如枚举该数的所有因数,再比如可以用埃氏筛和欧拉筛进行优化。国庆想考验下国豪对于素数的理解和应用能力。于是,他提了一个问题:给定一个合数 c,请国豪统计这个合数 c 的质因数个数、每个质因数及其出现的次数。
输入:
共一行,一个正整数 c。
输出:
若干行。第一行表示 c 的质因数的个数。接下来若干行,按照字典序
给出 c 的每个质因数及其出现的次数。
样例输入:
600
样例输出:
3
2 3
3 1 5 2
说明:
600=2 3 *3*5 2 ,600 有三个质因数,从小到大依次是 2,3,5,其中 2 出
现了 3 次,3 出现了 1 次,5 出现了 2 次。
数据范围:
4<=c<=2000000000
题解:
        分解某个数的质因数,我们一般使用while循环而不是for循环,原因是for循环找到的是因子而不一定是质因子,用while循环就便于寻找质因子。想到用while循环,那本题就迎刃而解了。
参考程序:
#include 
#include 
using namespace std;

int c,t,cnt=0,k=0,flag;
int a[100005]={0},b[100005]={0};

int main(){
	//freopen("prime.in","r",stdin);
	//freopen("prime.out","w",stdout);
	
	cin>>c;
	t=c;  //用变量t暂存c的值 
	for(int i=2;i<=t/2;i++){
		flag=0;  //flag是状态标志,若能分解出质因子,则置为1
		//注意用while循环不要用for循环,否则求解出的是因子而不是质因子 
		while(c%i==0){
			flag=1;
			a[k]=i;
			b[k]++;
			c/=i;	
		}
		if(flag==1){
			cnt++;
			k++;
		}
	}
	cout<

第四题 采摘苹果

(apple.cpp)
        秋天到了,国豪家院子里的苹果树结了 n 个果子。国豪准备采摘这些苹果。他有一个 a 厘米高的椅子,当他手够不着时,他会站到椅子上再试试。当然,摘苹果不仅需要能够到,还需要消耗一定的体力值。国豪初始的体力值为 s。如果椅子的高度 a 再加上他手伸直的最大长度 b 大于等于第 i 个苹果的高度 xi,并且国豪目前现有的体力值大于等于摘第 i 个苹果消耗的体力值 yi 时,就认定国豪能够摘到这个苹果。请你编程统计国豪一共能摘到多少个苹果。
输入:
共 n+2 行。第 1 行,两个正整数 n 和 s。第 2 行,两个正整数 a 和 b。
接下来的 n 行,每行两个正整数 xi 和 yi。
输出:
共一行,一个整数,表示国豪最多能摘到的苹果数。
样例输入:
4 10 20 140
150 4
170 2
130 5
155 3
样例输出:
2
说明:
一共有 4 个苹果。国豪初始的体力值为 10。国豪能摘到苹果的最大高度为 160。第 2 个苹果超过了 160,国豪摘不到。剩下的 3 个苹果, 虽然都能摘到,但他的体力值只能保证他摘 2 个。
数据范围:
n<=5000,a<=50,b<=200,s<=1000,xi<=280,yi<=100
题解:
        本题需要存储的数据比较多,不过只要理清思路也不复杂。要注意,题目要求的是 国豪最多能摘到的苹果数,国豪每摘到一个苹果都会消耗一定的体力值,因此,为了尽可能多的摘到苹果,我们需要用到贪心算法,而本题的贪心策略就是优先去摘那些对体力消耗较小的苹果,这样下来,局部最优解可产生整体最优解。如何分辨对体力消耗较小的苹果呢?那我们很自然地想到排序,将yi从小到大排序,注意排序时相应的xi也要发生位置变化,因此我们可以使用冒泡排序来解决此问题。
参考程序:
#include 
using namespace std;

int main(){
	//freopen("apple.in","r",stdin);
	//freopen("apple.out","w",stdout);
	
	int n,s,a,b,cnt=0,i,j,t1,t2;
	int x[5005],y[5005];
	cin>>n>>s;
	cin>>a>>b;
	for(int i=0;i>x[i]>>y[i];
	}
	
	//按体力值进行冒泡排序
	for(i=0;iy[j+1]){
				t1=x[j];x[j]=x[j+1];x[j+1]=t1;
				t2=y[j];y[j]=y[j+1];y[j+1]=t2;
			}
		}
	} 
	
	for(i=0;i=x[i]&&s>=y[i]){
			cnt++;
			s-=y[i];  //注意:摘到后体力要被消耗 
		}
	}
	cout<

你可能感兴趣的:(信息学,算法,c++)