第十一届蓝桥杯省赛B组c/c++

文章提供了若干编程试题的解答,包括门牌号字符统计、计算既约分数的数量、蛇形填数问题、跑步总距离计算、成绩的及格率和优秀率统计、回文日期查找以及子串分值和和平面切分问题的解决方案。这些题目涵盖了数学和算法应用。
摘要由CSDN通过智能技术生成

试题A:门牌制作

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

answer:624

#include <bits/stdc++.h>
using namespace std;
int cnt;
int main(){
	int i,n;
	for(i=1;i<=2020;i++){
		n=i;
		do{
			if(n%10==2){
				cnt++;
			}
			n=n/10;
		}while(n!=0);
	}
	cout << cnt << endl;
	return 0;
}

 

试题B:既约分数(欧几里得算法)

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

answer:2481215

 c++实现:

#include <bits/stdc++.h>
using namespace std;
int cnt;
int main(){
	int i,j;
	for(i=1;i<=2020;i++){
		for(j=1;j<=2020;j++){
			if(__gcd(i,j)==1){
				cnt++;
			}
		}
	}
	cout << cnt << endl;
	return 0;
}

 c实现:

#include <stdio.h>

int main(){
	int cnt=0;
	int i,j,temi,temj,t,tem;
	for(i=1;i<=2020;i++){
		for(j=1;j<=2020;j++){
			temi=i,temj=j;
			if(temi<temj){
				t=temi;
				temi=temj;
				temj=t;
			}
			while(temi%temj!=0){
				tem=temi%temj;
				temi=temj;
				temj=tem;
			}
			if(temj==1)cnt++;
		}
	}
	printf("%d\n",cnt);
	return 0;
}

 试题C:蛇形填数

如下图所示,小明用从 1 开始的正整数 “蛇形” 填充无限大的矩阵。
在这里插入图片描述

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

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

int main(){
	int r=1,c=1,i;
	for(i=2;i<=1000;i++){
		if((r+c)%2==0){
			if(r==1){
				c=c+1;
			}else{
				r=r-1;
				c=c+1;
			}
		}
		else{
			if(c==1){
				r=r+1;
			}else{
				r=r+1;
				c=c-1;
			}
		}
		if(r==20 && c==20)break;
	}
	cout << i << endl;
	return 0;
}

试题D:跑步锻炼 

小蓝每天都锻炼身体。正常情况下,小蓝每天跑 1 千米。如果某天是周一或者月初(1 日),为了激励自己,小蓝要跑 2 千米。如果同时是周一或月初,小蓝也是跑 2 千米。

小蓝跑步已经坚持了很长时间,从 2000 年 1 月 1 日周六(含)到 2020 年10 月 1 日周四(含)。请问这段时间小蓝总共跑步多少千米?

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

int main(){
	int D[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
	int week=6,y,m,d,cnt;
	for(y=2000;y<=2020;y++){
		if(y%4==0&&y%100!=0 || y%400==0){
			D[2]=29;
		}else{
			D[2]=28;
		}
		for(m=1;m<=(y==2020?10:12);m++){
			for(d=1;d<=(y==2020&&m==10?1:D[m]);d++){
				if(week==1 || d==1){
					cnt+=2; 
				}else{
					cnt+=1;
				}
				week=(week+1)%7;
			}
		}
	}
	cout << cnt << endl;
	return 0;
}

 

 试题F:成绩统计

【问题描述】
小蓝给学生们组织了一场考试,卷面总分为 100 分,每个学生的得分都是一个 0 到 100 的整数。

如果得分至少是 60 分,则称为及格。如果得分至少为 85 分,则称为优秀。

请计算及格率和优秀率,用百分数表示,百分号前的部分四舍五入保留整 数。

【输入格式】
输入的第一行包含一个整数 n,表示考试人数。

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

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

【样例输入】

7

80

92

56

74

88

100

0

【样例输出】

71%

43%

【评测用例规模与约定】

对于50%的评测用例,1<=n<=100。

对于所有评测用例,1<=n<=10000。

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

int main(){
	int i,a,n,cnt1=0,cnt2=0;
	int r1,r2,r3;
	cin >> n;
	for(i=0;i<n;i++){
		cin >> a;
		if(a>=85)cnt1++;
		if(a>=60)cnt2++;
	}
	r1=(cnt1*100.0)/n+0.5;
	r2=(cnt2*100.0)/n+0.5;
	r3=3.3;
	cout << r2 << "%\n" << r1 << "%\n" << endl;
	return 0;
}

 

 试题G:回文日期

        2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2 日。因为如果将这个日期按 “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

【评测用例规模与约定】
对于所有评测用例,10000101≤N≤89991231,保证 N是一个合法日期的 8 位数表示。

#include <bits/stdc++.h>
using namespace std;
bool ok(string s);
bool check(int y);

int main(){
	int D[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
	string S,ans1="",ans2="";
	cin >> S;
	int i,m,d;
	for(i=stoi(S.substr(0,4));ans1==""||ans2=="";i++){
		string s=to_string(i),t=to_string(i);
		reverse(t.begin(),t.end());
		s=s+t;
		m=stoi(s.substr(4,2)),d=stoi(s.substr(6,2));
		if(check(i)){
			D[2]=29;
		}else{
			D[2]=28;
		}
		if(s<=S) continue;
		if(m<1||m>12) continue;
		if(d<1||d>D[m]) continue;
		if(ans1=="")ans1=s;
		if(ok(s)&&ans2=="")ans2=s;
	}
	cout << ans1 << '\n' << ans2 << endl;
	return 0;
}

bool ok(string s){
	if(s[0]==s[2] && s[1]==s[4]){
		return true;
	}else{
		return false;
	}
}

bool check(int y){
	if(y%4==0&&y%100!=0 || y%400==0){
		return true;
	}else{
		return false;
	}
}

 

 试题H:子串分值和

【题目描述】
        
对于一个字符串 S SS,我们定义 S SS 的分值 f ( S ) f(S)f(S) 为 S SS 中出现的不同的字符个数。例如 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

暴力解法(运行超时,通过率40%)
#include <bits/stdc++.h>
using namespace std;

int main(){
	string S;
	cin >> S;
	int l,r,k,n=S.size(),ans=0;
	for(l=0;l<n;l++){
		for(r=0;r<n;r++){
			unordered_set<char> s;
			for(k=r;k<=l;k++){
				s.insert(S[k]);
			}
			ans+=s.size();
		}
	}
	cout << ans << endl;
	return 0;
}
正确解法
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int last[200];
ll ans;

int main(){
	string S,s;
	cin >> S;
	s=" "+S;
	int l,n=S.size();
	for(l=1;l<=n;l++){
		ans+=(ll)(l-last[s[l]])*(n-l+1);
		last[s[l]]=l; 
	}
	cout << ans << endl;
	return 0;
}

 

 试题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。

#include <bits/stdc++.h>
using namespace std;
long long ans;
long double s[1000][2];
bool st[1000];
pair<long double,long double> p;

int main(){
	int n,i,j;
	cin >> n;
	for(i=0;i<n;i++){
		cin >> s[i][0] >> s[i][1];
		set <pair<long double,long double> > points;
		for(j=0;j<i;j++){
			if(st[j]==1)continue;
			if(s[i][0]==s[j][0]){
				if(s[i][1]==s[j][1]){
					st[i]=1;
					break;
				}else continue;
			}
			p.first=(s[j][1]-s[i][1])/(s[i][0]-s[j][0]);
			p.second=s[i][0]*p.first+s[i][1];
			points.insert(p);
		}
		if(st[i]==0)ans+=points.size()+1;
	} 
	cout << ans+1 << endl;
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值