第十一届蓝桥杯B组C/C++省赛第二场(供个人复习时使用)

2022/1/28 20:05:21

本文主要是介绍第十一届蓝桥杯B组C/C++省赛第二场(供个人复习时使用),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

记录自己的进步,所有的题目是在自己的理解上写出代码,不会的地方也在其他博客上有参考,代码提交答案是否完全或者很大程度上的正确不敢说有绝对的保证,主要用来写给自己看,加深印象,如果能够帮到其他人那就更好啦!!!

试题A:门牌制作(答案:624)

题目描述:
小蓝要为一条街的住户制作门牌号。这条街一共有2020位住户,门牌号从1到2020编号。小蓝制作门牌的方法是先制作0到9这几个数字字符,最后根据需要将字符粘贴到门牌上,例如门牌1017需要依次粘贴字符1、0、1、7,即需要1个字符0,2个字符1,1个字符7。请问要制作所有的1到2020号门牌,总共需要多少个字符2?

考点:如何取出数字的每一位

(1)此题代码:

#include<iostream>
using namespace std;
int main()
{
	int count=0;
	for(int i=1;i<=2020;i++)
	{
		if(i%10==2)
		count++;
		if(i/10%10==2)
		count++;
		if(i/100%10==2)
		count++;
		if(i/1000%10==2)
		count++;
	}
	cout<<count;
}

这个题最大就是2020,最多只有四位数,但是如果题目给了一个很大的数我们根本难以每一个位数的去列举,这时候就要寻找更好的办法解决,下边的代码既适合这个题目也同样适合位数更多的数字求解。因为比赛的原因,所以上述代码很容易就想到了,也很直接就敲出来了,下边的如果一开始就能想到当然更好啦!

(2)多位数求解

#include<iostream>
using  namespace std;
int weishu(int a)//用一个函数来判每一位是否为2
{
	int cot=0;
	while(a)
	{
		if(a%10==2)
		cot++;
		a/=10;
	}
	return cot;	 
} 
int main()
{
	int count=0;
	for(int i=1;i<=2020;i++)
	{
	count+=weishu(i);	
	} 
	cout<<count;
}

试题B:既约分数(答案:2481215)

题目描述:
如果一个分数的分子和分母的最大公约数是1,这个分数称为既约分数。例如,3/4,5/2,1/8,7/1都是既约分数。请问,有多少个既约分数,分子和分母都是1到2020之间的整数(包括1和2020)

考点:最大公约数


(1)此题代码

#include<iostream>
using  namespace std;
int gcd(int a,int b)//辗转相除法求最大公约数
{
	if(a%b==0)
	return b;
	else
	return gcd(b,a%b);
}
int main()
{
	int count=0;
	for(int i=1;i<=2020;i++)//双重循环来判断
	{
		for(int j=1;j<=2020;j++)
		{
			if(gcd(i,j)==1)
			count++; 
		}
	}
	cout<<count;
}

(2)此处附上求最小公倍数的代码

//1用原始代码求最小公倍数
#include<iostream>
using  namespace std;
int lcm(int a,int b)
{
	int max;
	max=(a>b)?a:b;
	while(true)
	{
	if(max%a==0&&max%b==0)
	return max;
	max++;
    }	
}
int main()
{
	int a=3;
	int b=7;
	cout<<lcm(a,b);
}
//2利用最大公约数求最小公倍数(同时也应该了解了用后者求前者了)
#include<iostream>
using  namespace std;
int gcd(int a,int b)
{
	if(a%b==0)
	return b;
	else
	return gcd(b,a%b);
}
int lcm(int a,int b)
{
	return (a*b)/gcd(a,b);
}
int main()
{
	int a=3;
	int b=7;
	cout<<lcm(a,b);
}

试题C:蛇形填数(761)

题目描述:

如下图所示,小明用从 1 开始的正整数“蛇形”填充无限大的矩阵。
1 2 6 7 15 …
3 5 8 14 …
4 9 13 …
10 12 …
11 …

容易看出矩阵第二行第二列中的数是 5。请你计算矩阵中第 20 行第 20 列
的数是多少?

考点:找规律!当然了填空题可以直接找规律就可,但是蛇形填数的题的种类很多,值得认真做一做!

(1)此题代码

如图,这个题降低了难度,问的是20行20列,还在题目中给提示了一下,第2行第2列的数是5,那我们可以看到列数和行数相等:

第1行第1列:1

第2行第2列:5(1+1*4)

第3行第3列:13(1+1*4+2*4)

......

第n行第n列:(1+1*4+2*4+3*4+......+(n-1)*4)

#include<iostream>
using  namespace std;
int main()//相当于用代码表达一个计算器,我们直接就把此题转换为了求和
{
	int sum=1;
     for(int i=1;i<=20;i++)
     {
     	sum+=(i-1)*4;
     }
	 cout<<sum;
}

(2)适合此类题的代码

#include<iostream>
#include<cstring>
using namespace std;
int a[100][100],count;
int main()
{
     for(int k=2;k<=40;k++)//
     for(int i=1;i<k;i++)
     {
     	if(k%2)
     	a[i][k-i]=++count;//如果k%2=1的话,说明在斜着看的偶数行,此时数按大小从右上向左下方开始填
           //(因为从整个的数组中可以看到奇数行有奇数个数字,偶数行有
           //  偶数个数字,i在这里就显示了有多少个数字,想一下,
           //  如果k%2=1,说明k是奇数,i=1;i<k,那么就有偶数个i,
           //  是不是就说明i代表了偶数个数字,就在偶数行),
     	else
     	a[k-i][i]=++count;//如果k%2=0的话,说明在斜着看的奇数行,此时数按大小从左下向右上方开始填
	 }
	 cout<<a[20][20];
	 return 0;
}

试题D :跑步锻炼(8879)

题目描述:

小蓝每天都锻炼身体。
正常情况下,小蓝每天跑 1 千米。如果某天是周一或者月初(1 日),为了
激励自己,小蓝要跑 2 千米。如果同时是周一或月初,小蓝也是跑 2 千米。
小蓝跑步已经坚持了很长时间,从 2000 年 1 月 1 日周六(含)到 2020 年
10 月 1 日周四(含)。请问这段时间小蓝总共跑步多少千米?

考点:日期判断

(1)excle解决:不会!!!

(2)一般方法

#include<iostream>
using namespace std;
int M[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
//下边m初始值设为了1,即从1月开始,但数组一般从0开始,所以多设置了一个月份 
int main()
{
	int y=2000,m=1,d=1,w=6,ans=0;
	while(y!=2020||m!=10||d!=1)
	{
		if(y%400==0||(y%4==0&&y%100!=0))//闰年的判断 
		{
		M[2]=29;//闰年二月29天 
	        }
		else
		{
		M[2]=28;
	        }
		d++;
              //直接从第二天开始 
		w=(w+1)%7;
             //算周几,代入算一下。这种表达方法在很多题中都有使用到,不限于日期表达 
		if(d>M[m])//如果天数超出这个月的天数那么自动天数归一,月数加1 
		{
			d=1;
			m++;
		}
		if(m>12)
             //如果月数超出了12月份,那么月数归1,年数加1 
		{
			m=1;
			y++;
		}
		if(d==1||w==1)
             //如果一个月的第一天或者是周一,那么ans计数加1
             //因为下边还会有每天都加1,所以只需要在这里限定一下特殊的日子再多加一天即可 
		{
		        ans++;
	        }
	
	                ans++;
            // 正常的话每天加1,也正因为这里每天都加1,所有上边特殊的日子只需要加1就可以 
	}
                        ans+=2;
            //因为直接就d++了,并没算2000.1.1这一天的,所以需要单独加上2,或者可以直接初始化ans=2 就不需要在加了 
                        cout<<ans<<endl;
                        return 0;
 } 

试题E :七段码(本渣感觉这个题很难!)

题目描述:

上图给出了七段码数码管的一个图示,数码管中一共有 7 段可以发光的二 极管,分别标记为 a,b,c,d,e,f,g。

小蓝要选择一部分二极管(至少要有一个)发光来表达字符。在设计字符 的表达时,要求所有发光的二极管是连成一片的。

例如:b

发光,其他二极管不发光可以用来表达一种字符。

例如:c

发光,其他二极管不发光可以用来表达一种字符。

这种方案与上 一行的方案可以用来表示不同的字符,尽管看上去比较相似。

例如:a,b,c,d,e

发光,f,g

不发光可以用来表达一种字符。

例如:b,f

发光,其他二极管不发光则不能用来表达一种字符,因为发光 的二极管没有连成一片。

请问,小蓝可以用七段码数码管表达多少种不同的字符?

2020第十一届蓝桥杯软件类省赛第二场C/C++ 大学 B 组 E: 七段码(DFS,二进制枚举+并查集判重) - liyexin - 博客园

试题F :成绩统计

题目描述:

小蓝给学生们组织了一场考试,卷面总分为 100 分,每个学生的得分都是 一个 0 到 100 的整数。 如果得分至少是 60 分,则称为及格。如果得分至少为 85 分,则称为优秀。 请计算及格率和优秀率,用百分数表示,百分号前的部分四舍五入保留整 数。

【输入格式】

输入的第一行包含一个整数 n,表示考试人数。 接下来 n 行,每行包含一个 0 至 100的整数,表示一个学生的得分。

【输出格式】

输出两行,每行一个百分数,分别表示及格率和优秀率。百分号前的部分四舍五入保留整数。

考点:round()函数四舍五入取整

(1)代码

#include<iostream>
#include<cmath>
using namespace std;
int main()
{
	double a[20];
	double count1=0,count2=0;
	double n;//这个地方定义为浮点型方便后边使用除法
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
		if(a[i]>=60&&a[i]<85)
		count1++;
		else if(a[i]>=85)
		count2++;
		else
		continue;
	}
	cout<<round(count1/n*100)<<"%"<<endl;
	cout<<round(count2/n*100)<<"%";
	
}

试题G: 回文日期

题目描述:

2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 24 日。因为如果将这个日期按 "yyyymmdd" 的格式写成一个 8 位数是 20200202, 恰好是一个回文数。我们称这样的日期是回文日期。 有人表示 20200202 是 “千年一遇” 的特殊日子。对此小明很不认同,因为 不到 2 年之后就是下一个回文日期:20211202 即 2021 年 12 月 2 日。 也有人表示 20200202 并不仅仅是一个回文日期,还是一个 ABABBABA 型的回文日期。对此小明也不认同,因为大约 100 年后就能遇到下一个 ABABBABA 型的回文日期:21211212 即 2121 年 12 月 12 日。算不上 “千 年一遇”,顶多算 “千年两遇”。 给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个 ABABBABA 型的回文日期各是哪一天。

【输入格式】

输入包含一个八位整数 N,表示日期。

【输出格式】

输出两行,每行 1个八位数。第一行表示下一个回文日期,第二行表示下 一个 ABABBABA型的回文日期。

【样例输入】

20200202

【样例输出】

20211202
21211212

考点:日期加回文串加取位数(个人理解哈哈哈),貌似考了什么流转换!

(1)此题错误代码

以为很简单,唰唰写完了,后来发现大错特错:①没有看好题目,题目要求格式必须为日期格式,年月日的大小都有要求;②判断ABABBABA型没有排除AAAAAAAA型。

#include<iostream>
using namespace std;
int main()
{
	int n;
	cin>>n;
	int a,b,c,d,e,f,g,h;
	bool flag=1;
	do
	{
        n++;
		h=n%10;
		g=n/10%10;
		f=n/100%10;
		e=n/1000%10;
		d=n/10000%10;
		c=n/100000%10;
		b=n/1000000%10;
		a=n/10000000%10;
		if(a==h&&b==g&&c==f&&d==e)//结合ABCDDCBA的特点判断
		{
		cout<<a<<b<<c<<d<<e<<f<<g<<h<<endl;
		flag=0;//一旦找到第一个直接结束循环即可
     	}
     	else
     	flag=1;	
	}while(flag);
	do
	{
        n++;
		h=n%10;
		g=n/10%10;
		f=n/100%10;
		e=n/1000%10;
		d=n/10000%10;
		c=n/100000%10;
		b=n/1000000%10;
		a=n/10000000%10;
		if(a==c&&c==f&&f==h&&b==d&&d==e&&e==g)//结合ABABBABA型的特点判断
		{
		cout<<a<<b<<c<<d<<e<<f<<g<<h;
		flag=0;//一旦找到第一个直接结束循环即可
     	}
     	else
     	flag=1;	
	}while(flag);
	
}

(2)正确代码(比较死板的写法)

(个人完全参照上边的日期处理写的代码,提交是否会正确这个很难说,如果有错误还希望大佬评论区里予以指教!!!,因为水平有限,代码看起来也会比较笨重,但是从一开始的根本没思路到现在的用很长时间能够写出来,已经是一种进步了吧!)

#include<iostream>
using namespace std;
int M[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int isleapyear(int y)///判断是否为闰年 
{
	if(y%400==0||(y%4==0&&y%100!=0))
	{
		return 1;
	}
	else
	return 0;
} 
int main()//以下拿2020 0202做例子 
{
	int day;//输入这一天 
	cin>>day;
	int a,b1,b2,b3,b4,m,d;
	a=day/10000%100000;//取前四位 ,即a=2020 
	b1=day/1000%10;//取后四位,b1=0
	b2=day/100%10;//b2=2
	b3=day/10%10;//b3=0
	b4=day%10;//b4=2
	m=b1*10+b2;//日期m,m=2(这里是2,不是02也没关系,后边再设置别的方法取出每一位) 
	d=b3*10+b4;//天d,d=2 
	do{
		if(isleapyear(a))//判断是否为闰年 
		M[2]=29;
		else
		M[2]=28;
		d++;//先向后走,首先天数加1 
		if(d>M[m])//这里的处理和上边的“跑步锻炼”的日期处理一样 
		{
			d=1;;
			m++;
		}
		if(m>12) 
		{
			m=1;
			a++;
		}
		
		int c1=d%10;//先看下边的第一个if里的内容 
		int c2=d/10%10;
		int c3=m%10;
		int c4=m/10%10;
		if(a==c1*1000+c2*100+c3*10+c4)//2020 0202,a=2020,只需要把后边的四位数分别乘以位数加起来判断是否相等即可,因此在上边定义c来取出位数 
		{
		cout<<a*10000+m*100+d<<endl;//这里的m和d都是变化后的了,可以乘以位数直接输出 
		break;
		}
	}while(1);
	
	do{//前部分同上,为什么这里又进行了一次do...while循环,
	//因为我好像不会在一个循环里输出第一种回文类型后结束此进程再执行输出第二种回文类型的操作!!! 
	//所以上边直接用了break; 
		if(isleapyear(a))
		M[2]=29;
		else
		M[2]=28;
		d++;
		if(d>M[m])
		{
			d=1;;
			m++;
		}
		if(m>12) 
		{
			m=1;
			a++;
		}
		
		int c1=d%10;
		int c2=d/10%10;
		int c3=m%10;
		int c4=m/10%10;
		int c5=a%10;
		int c6=a/10%10;
		int c7=a/100%10;
		int c8=a/1000%10;
		if((c8==c6&&c6==c1&&c3==c1)&&(c7==c5&&c5==c4&&c4==c2)&&(c8!=c7))//这个时候就需要取出每一位来进行比较了,因此上边c取出每一位 
		{
		cout<<a*10000+m*100+d;
		break;
		}
	}while(1);
	
	return 0;
}

试题H: 子串分值和

题目描述:

对于一个字符串 S,我们定义 S 的分值 f(S) 为 S 中出现的不同的字符个 数。例如 f(”aba”)=2,f(”abc”)=3,f(”aaa”)=1。 现在给定一个字符串 S[0..n−1](长度为 n),请你计算对于所有 S 的非空 子串 S[i..j](0≤i≤j<n),f(S[i..j])

的和是多少。

【输入格式】

输入一行包含一个由小写字母组成的字符串 S。

【输出格式】

输出一个整数表示答案。

【样例输入】

ababc

【样例输出】

28

【样例说明】

子串 	   f值
a 	    1
ab 	    2
aba 	    2
abab 	    2
ababc 	    3
b 	    1
ba          2
bab         2
babc        3
a           1
ab          2
abc         3
b           1
bc          2
c           1 

【评测用例规模与约定】

对于 20的评测用例,1≤n≤10;

对于 40的评测用例,1≤n≤100;

对于 50的评测用例,1≤n≤1000;

对于 60的评测用例,1≤n≤10000;

对于所有评测用例,1≤n≤100000。

考点:。。。每个字符的贡献度?

(1)此题代码(不好测试,代码虽然最终答案正确但是可能会由于复杂度和各种原因不是完全符合题目要求,只是提供一种思路,希望不要带偏别人!)看了好多其他大佬的解法发现这种解法虽然答案正确,但是不够优化,最后无法通过,正确的还是计算每个字符的贡献度,学习之后再来更新!

#include<iostream>//
#include<cstring>
#include<set>//利用set实现计数(set可去重) 
using namespace std;
long long count=0;
int cot(string s)//单独的函数拿出来计数 
{
  set<string>st;//定义一个set集合 
  for(int j=1;j<=s.size();j++)
     {
	for(int i=0;i<=s.size()-j;i++)
	//可以拿最简单的abc在纸上写出每一个步骤举例子,简单易懂 
	{
        string w=s.substr(i,j);
        //前两个for循环先从整个字符串分别提取出每个小的字符串来 
        for(int t=0;t<w.size();t++)//第三个for循环是实现小的字符串的计数 
           {
	     st.insert(w.substr(t,1));
           }
	     count+=st.size();//计数相加 
	     st.clear();
             //一定要记得每次记完一个小的字符串个数都要清空set集合,不然下一次无法重新计数 
	 }
      } 
	return count;	
}
int main()
{
	
	string s;
	cin>>s;
        cout<<cot(s);	
} 

试题I:平面切分

题目描述:

平面上有 N 条直线,其中第 i 条直线是 y=Ai⋅x+Bi。 请计算这些直线将平面分成了几个部分。

【输入格式】

第一行包含一个整数 N以下 N 行,每行包含两个整数 Ai,Bi。

【输出格式】

一个整数代表答案。

【样例输入】

3
1 1
2 2
3 3

【样例输出】

6

【评测用例规模与约定】

对于 50的评测用例,1≤N≤4, −10≤Ai,Bi≤10。 对于所有评测用例,1≤N≤1000,−100000≤Ai,Bi≤100000。

蓝桥杯 平面切分_u013098139的博客-CSDN博客_蓝桥杯平面切分



这篇关于第十一届蓝桥杯B组C/C++省赛第二场(供个人复习时使用)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程