2022年蓝桥杯省赛 C++ C组

New Online Judge 做题网站

试题 A: 排列字母

本题总分: 5
【问题描述】
小蓝要把一个字符串中的字母按其在字母表中的顺序排列。
例如, LANQIAO 排列后为 AAILNOQ
又如, GOODGOODSTUDYDAYDAYUP 排列后为 AADDDDDGGOOOOPSTUUYYY
请问对于以下字符串,排列之后字符串是什么?
WHERETHEREISAWILLTHEREISAWAY
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个由大写字母组成的字符串,在提交答案时只填写这个字符串,填写多余的内
容将无法得分。

题解:

#include<iostream>
#include<string>
#include<cstdio>
using namespace std;
string str;
int a[103];

int main(){
	str="WHERETHEREISAWILLTHEREISAWAY";
	for(int i=0;i<str.size();i++){
		a[str[i]]++;
	}
	for(int i='A';i<='Z';i++){
		for(int j=1;j<=a[i];j++) printf("%c",i);
	}
	return 0;
}
// AAAEEEEEEHHHIIILLRRRSSTTWWWY

试题 B: 特殊时间

本题总分: 5
【问题描述】
2022 2 22 22:20 是一个很有意义的时间,年份为 2022 ,由 3 2
1 0 组成,如果将月和日写成 4 位,为 0222 ,也是由 3 2 1 0
成,如果将时间中的时和分写成 4 位,还是由 3 2 1 0 组成。
小蓝对这样的时间很感兴趣,他还找到了其它类似的例子,比如 111 10
11 01:11 2202 2 22 22:02 等等。
请问,总共有多少个时间是这种年份写成 4 位、月日写成 4 位、时间写成
4 位后由 3 个一种数字和 1 个另一种数字组成。注意 1111 11 11 11:11
不算,因为它里面没有两种数字。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

题解:

#include<iostream>
#include<string>
#include<cstdio>
using namespace std;
int a[5][3];
int ans;

void solve(int x,int y){
	a[1][1]=y*10+x,a[1][2]=x*10+x;
	a[2][1]=x*10+y,a[2][2]=x*10+x;
	a[3][1]=x*10+x,a[3][2]=y*10+x;
	a[4][1]=x*10+x,a[4][2]=x*10+y;
	for(int i=1;i<=4;i++){
		if(!(a[i][1]>0&&a[i][1]<=12&&a[i][2]>0&&a[i][2]<=30)) continue ;
		for(int j=1;j<=4;j++){
			if(!(a[j][1]<=24&&a[j][2]<=60)) continue ;
			ans++;
//			printf("%02d%02d %02d:%02d\n",a[i][1],a[i][2],a[j][1],a[j][2]);
		}
	}
}

int main(){
	for(int i=1;i<=9;i++){
		solve(0, i);
		solve(i,0);
	}
	for(int i=2;i<=9;i++){
		solve(1, i);
		solve(i, 1);
	}
	cout<<ans*4;
	return 0;
}

// 212

试题 C: 纸张尺寸

时间限制 : 1.0s
内存限制 : 256.0MB
本题总分: 10
【问题描述】
ISO 国际标准中定义了 A0 纸张的大小为 1189 mm × 841 mm ,将 A0
沿长边对折后为 A1 纸,大小为 841 mm × 594 mm ,在对折的过程中长度直接取
下整(实际裁剪时可能有损耗)。将 A1 纸沿长边对折后为 A2 纸,依此类推。
输入纸张的名称,请输出纸张的大小。
【输入格式】
输入一行包含一个字符串表示纸张的名称,该名称一定是 A0 A1 A2
A3 A4 A5 A6 A7 A8 A9 之一。
【输出格式】
输出两行,每行包含一个整数,依次表示长边和短边的长度。
【样例输入 1
A0
【样例输出 1
1189
841
【样例输入 2
A1
【样例输出 2
841
594

题解:

#include<iostream>
using namespace std;
char ch;
int mxl=1189,mnl=841,t;

int main(){
	cin>>ch>>ch;
	for(int i=1;i<=ch-'0';i++){
		t=mxl/2;
		mxl=max(t, mnl);
		mnl=min(t, mnl);
	}
	cout<<mxl<<endl<<mnl;
	return 0;
}

试题 D: 求和

时间限制 : 1.0s
内存限制 : 256.0MB
本题总分: 10
【问题描述】
给定 n 个整数 a 1 , a 2 , · · · , a n ,求它们两两相乘再相加的和,即
S = a 1 · a 2 + a 1 · a 3 + · · · + a 1 · a n + a 2 · a 3 + · · · + a n 2 · a n 1 + a n 2 · a n + a n 1 · a n .
【输入格式】
输入的第一行包含一个整数 n
第二行包含 n 个整数 a 1 , a 2 , · · · a n
【输出格式】
输出一个整数 S ,表示所求的和。请使用合适的数据类型进行运算。
【样例输入】
4
1 3 6 9
【样例输出】
117
【评测用例规模与约定】
对于 30 % 的数据, 1 n 1000 1 a i 100
对于所有评测用例, 1 n 200000 1 a i 1000

题解: 

分析:先求前缀和,再让每个前缀和 和 数组元素相乘。

#include<iostream>
using namespace std;
long long n,sum,s[200003],a[200003];

int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		s[i]=s[i-1]+a[i];
	}
	for(int i=2;i<=n;i++){
		sum+=s[i-1]*a[i];
	}
	cout<<sum;
	return 0;
}

试题 E: 数位排序

时间限制 : 1.0s
内存限制 : 256.0MB
本题总分: 15
【问题描述】
小蓝对一个数的数位之和很感兴趣,今天他要按照数位之和给数排序。当
两个数各个数位之和不同时,将数位和较小的排在前面,当数位之和相等时,
将数值小的排在前面。
例如, 2022 排在 409 前面,因为 2022 的数位之和是 6 ,小于 409 的数位
之和 13
又如, 6 排在 2022 前面,因为它们的数位之和相同,而 6 小于 2022
给定正整数 n m ,请问对 1 n 采用这种方法排序时,排在第 m 个的元
素是多少?
【输入格式】
输入第一行包含一个正整数 n
第二行包含一个正整数 m
【输出格式】
输出一行包含一个整数,表示答案。
【样例输入】
13
5
【样例输出】
3
【样例说明】
1 13 的排序为: 1, 10, 2, 11, 3, 12, 4, 13, 5, 6, 7, 8, 9 。第 5 个数为 3
【评测用例规模与约定】
对于 30 % 的评测用例, 1 m n 300
对于 50 % 的评测用例, 1 m n 1000
对于所有评测用例, 1 m n 10^ 6

题解:

#include<iostream>
#include<algorithm>
using namespace std;
struct Node{
	int s,data;
}a[1000003];
int n,m;

bool cmp(Node x, Node y){
	if(x.s==y.s) return x.data<y.data;
	return x.s<y.s;
}

int gets(int x){
	int s=0;
	while(x){
		s+=x%10;
		x/=10;
	}
	return s;
}

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		a[i].data=i;
		a[i].s=gets(i);
	}
	sort(a+1,a+n+1,cmp);
	cout<<a[m].data;
	return 0;
}

试题 F: 选数异或

时间限制 : 1.0s
内存限制 : 256.0MB
本题总分: 15
【问题描述】
给定一个长度为 n 的数列 A 1 , A 2 , · · · , A n 和一个非负整数 x ,给定 m 次查
, 每次询问能否从某个区间 [ l , r ] 中选择两个数使得他们的异或等于 x
【输入格式】
输入的第一行包含三个整数 n , m , x
第二行包含 n 个整数 A 1 , A 2 , · · · , A n
接下来 m 行,每行包含两个整数 l i , r i 表示询问区间 [ l i , r i ]
【输出格式】
对于每个询问 , 如果该区间内存在两个数的异或为 x 则输出 yes , 否则输出
no
【样例输入】
4 4 1
1 2 3 4
1 4
1 2
2 3
3 3
【样例输出】
yes
no
yes
no
【样例说明】
显然整个数列中只有 2 , 3 的异或为 1
【评测用例规模与约定】
对于 20 % 的评测用例, 1 n , m 100
对于 40 % 的评测用例, 1 n , m 1000
对于所有评测用例, 1 n , m 100000 0 x < 2^ 20 1 l i r i n
0 A i < 2^ 20

题解:

分析:这是我暴力做的,过了40%。
#include<iostream>
using namespace std;
int n,m,x,l,r;
int a[100003];

int main(){
	cin>>n>>m>>x;
	for(int i=1;i<=n;i++) cin>>a[i];
	while(m--){
		cin>>l>>r;
		bool flag=true;
		for(int i=l;i<=r;i++){
			for(int j=i+1;j<=r;j++){
				if((a[i]^a[j])==x){
					flag=false;
					cout<<"yes"<<endl;
					break;
				}
			}
			if(!flag) break;
		}
		if(flag) cout<<"no"<<endl;
	}
	return 0;
}

学习了一些别人的博客,然后 AC 了100%。这里用了动态规划来做,然后要明白:

a^b=x =>  a^x=b 。

#include<iostream>
using namespace std;
int n,m,x,l,r,data;
//mp[i] 用于存取 i 出现的位置 
//dp[i] 用于存取 i 之前与当前数异或等于x的位置 
int mp[1<<20],dp[100002];

int main(){
	cin>>n>>m>>x;
	for(int i=1;i<=n;i++){
		cin>>data;
		dp[i]=max(dp[i-1], mp[data^x]);
		mp[data]=i;
	}
	while(m--){
		cin>>l>>r;
		if(dp[r]>=l) cout<<"yes"<<endl;
		else cout<<"no"<<endl;
	}
	return 0;
}

试题 G: 消除游戏

时间限制 : 1.0s
内存限制 : 256.0MB
本题总分: 20
【问题描述】
在一个字符串 S 中,如果 S i = S i 1 S i , S i +1 ,则称 S i S i +1 为边缘
字符。如果 S i , S i 1 S i = S i +1 ,则 S i 1 S i 也称为边缘字符。其它的字符
都不是边缘字符。
对于一个给定的串 S ,一次操作可以一次性删除该串中的所有边缘字符
(操作后可能产生新的边缘字符)。
请问经过 2 64 次操作后,字符串 S 变成了怎样的字符串,如果结果为空则
输出 EMPTY
【输入格式】
输入一行包含一个字符串 S
【输出格式】
输出一行包含一个字符串表示答案,如果结果为空则输出 EMPTY
【样例输入 1
edda
【样例输出 1
EMPTY
【样例输入 2
sdfhhhhcvhhxcxnnnnshh
【样例输出 2
s
【评测用例规模与约定】
对于 25 % 的评测用例, | S | ≤ 10 3 ,其中 | S | 表示 S 的长度;
对于 50 % 的评测用例, | S | ≤ 10 4
对于 75 % 的评测用例, | S | ≤ 10 5
对于所有评测用例, | S | ≤ 10 6 S 中仅含小写字母。

题解:

试题 H: 重新排序

时间限制 : 1.0s
内存限制 : 256.0MB
本题总分: 20
【问题描述】
给定一个数组 A 和一些查询 L i , R i ,求数组中第 L i 至第 R i 个元素之和。
小蓝觉得这个问题很无聊,于是他想重新排列一下数组,使得最终每个查
询结果的和尽可能地大。小蓝想知道相比原数组,所有查询结果的总和最多可
以增加多少 ?
【输入格式】
输入第一行包含一个整数 n
第二行包含 n 个整数 A 1 , A 2 , · · · , A n ,相邻两个整数之间用一个空格分隔。
第三行包含一个整数 m 表示查询的数目。
接下来 m 行,每行包含两个整数 L i R i ,相邻两个整数之间用一个空格分
隔。
【输出格式】
输出一行包含一个整数表示答案。
【样例输入】
5
1 2 3 4 5
2
1 3
2 5
【样例输出】
4
【样例说明】
原来的和为 6 + 14 = 20 ,重新排列为 (1 , 4 , 5 , 2 , 3) 后和为 10 + 14 = 24 ,增
加了 4
【评测用例规模与约定】
对于 30 % 的评测用例, n , m 50
对于 50 % 的评测用例, n , m 500
对于 70 % 的评测用例, n , m 5000
对于所有评测用例, 1 n , m 10^ 5 1 A i 10^ 6 1 L i R i 10^ 6

题解:

分析:这里由于数据有点大,暴力不能全部过,所以用了差分。(注意:int数据类型 * int数据类型赋值给 long long 类型,不能自动转换为long long,所以我就干脆全部设为long long 类型了)

#include<iostream>
#include<algorithm>
using namespace std;
const int N=100003;
long long n,num[N];
long long m,l,r,b[N],a[N];
long long s1,s2;

int main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>num[i];
	cin>>m;
	while(m--){
		cin>>l>>r;
		b[l]+=1;
		b[r+1]-=1;
	}
//	a数组存放的是当前位置查询的次数 
	for(int i=1;i<=n;i++){
		a[i]=a[i-1]+b[i];
		s1+=a[i]*num[i];
	}
	sort(num+1, num+n+1);
	sort(a+1, a+n+1);
	for(int i=1;i<=n;i++){
		s2+=a[i]*num[i];
	}
	cout<<s2-s1;
	return 0;
}

试题 I: 技能升级

时间限制 : 1.0s
内存限制 : 256.0MB
本题总分: 25
【问题描述】
小蓝最近正在玩一款 RPG 游戏。他的角色一共有 N 个可以加攻击力的技
能。其中第 i 个技能首次升级可以提升 A i 点攻击力,以后每次升级增加的点数
都会减少 B i A i/ B i ( 上取整 ) 次之后,再升级该技能将不会改变攻击力。
现在小蓝可以总计升级 M 次技能,他可以任意选择升级的技能和次数。请
你计算小蓝最多可以提高多少点攻击力?
【输入格式】
输入第一行包含两个整数 N M
以下 N 行每行包含两个整数 A i B i
【输出格式】
输出一行包含一个整数表示答案。
【样例输入】
3 6
10 5
9 2
8 1
【样例输出】
47
【评测用例规模与约定】
对于 40 % 的评测用例, 1 N , M 1000
试题 I: 技能升级
14 第十三届蓝桥杯大赛软件赛省赛 C/C++ 大学 C
对于 60 % 的评测用例, 1 N 10^ 4 , 1 M 10^ 7
对于所有评测用例, 1 N 10^ 5 1 M 2 × 10^ 9 1 A i , B i 10^ 6

题解: 

分析:我是通过暴力进行求解,AC了 40%,然后用二分进行了下优化,AC了 60%。

#include<iostream>
#include<algorithm>
using namespace std;
long long n,m;
long long s;

struct Node{
	int a,b;
}node[100003];

bool cmp(Node x,Node y){
	return x.a<y.a;
}

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>node[i].a>>node[i].b;
	}
	sort(node+1, node+n+1, cmp);
	while(m--){
		if(node[n].a<=0) break;
		s+=node[n].a;
		node[n].a-=node[n].b;
		int l=1,r=n-1,ta=node[n].a,tb=node[n].b;
		while(l<r){
			int mid=(l+r)>>1;
			if(node[mid].a<ta) l=mid+1;
			else r=mid;
		}
		if(l==n-1&&node[n-1].a<ta) continue ;
		for(int i=n-1;i>=l;i--){
			node[i+1].a=node[i].a;
			node[i+1].b=node[i].b;
		}
	}
	cout<<s;
	return 0;
}

试题 J: 重复的数

时间限制 : 1.0s
内存限制 : 256.0MB
本题总分: 25
【问题描述】
给定一个数列 A = ( a 1 , a 2 , · · · , a n ) ,给出若干询问,每次询问某个区间 [ l i , r i ]
内恰好出现 k i 次的数有多少个。
【输入格式】
输入第一行包含一个整数 n 表示数列长度。
第二行包含 n 个整数 a 1 , a 2 , · · · , a n ,表示数列中的数。
第三行包含一个整数 m 表示询问次数。
接下来 m 行描述询问,其中第 i 行包含三个整数 l i , r i , k i 表示询问 [ l i , r i ]
间内有多少数出现了 k i 次。
【输出格式】
输出 m 行,分别对应每个询问的答案。
【样例输入】
3
1 2 2
5
1 1 1
1 1 2
1 2 1
1 2 2
1 3 2
【样例输出】
1
0
2
0
1
【评测用例规模与约定】
对于 20 % 的评测用例, n , m 500 , 1 a 1 , a 2 , · · · , a n 1000
对于 40 % 的评测用例, n , m 5000
对于所有评测用例, 1 n , m 100000 , 1 a 1 , a 2 , · · · , a n 100000 , 1 l i
r i n , 1 k i n

题解: 

分析:暴力求解,AC了 20%。

#include<iostream>
#include<cstring>
using namespace std;
const int N=100002;
int n,m,a[N],l,r,k;
int num[N];

int main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	cin>>m;
	while(m--){
		cin>>l>>r>>k;
		memset(num, 0, sizeof(num));
		int cnt=0;
//		此处会超时 
		for(int i=l;i<=r;i++){
			num[a[i]]++;
			if(num[a[i]]==k) cnt++;
			else if(num[a[i]]==k+1) cnt--;
		}
		cout<<cnt<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值