第十二届蓝桥杯大赛软件赛决赛题解

Posted MangataTS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十二届蓝桥杯大赛软件赛决赛题解相关的知识,希望对你有一定的参考价值。

题目下载链接
注意,以下答案均为作者本人的答案,不是官方答案!!!(也就是说,可能(多半)是错的)

填空预览

25 1903 977 2607074472

试题 A: 带宽

##【问题描述】
小蓝家的网络带宽是 200 Mbps,请问,使用小蓝家的网络理论上每秒钟最
多可以从网上下载多少 MB 的内容。
##【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

解题思路:

常识 Mbps和MB换算为8Mbps = 1MB
200 / 8 = 25

试题 B: 纯质数

##【问题描述】
如果一个正整数只有 1 和它本身两个约数,则称为一个质数(又称素数)。
前几个质数是:2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, ···。
如果一个质数的所有十进制数位都是质数,我们称它为纯质数。例如:2,
3, 5, 7, 23, 37 都是纯质数,而 11, 13, 17, 19, 29, 31 不是纯质数。当然 1, 4, 35
也不是纯质数。
请问,在 1 到 20210605 中,有多少个纯质数?
##【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

解题思路:

暴力跑一下就出来了,我的答案是1903

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<iostream>
#define ll long long
using namespace std;



const int N = 2e7+10;
const int M = 20210605;

bool is_pr(ll k) {
	if(k == 0 || k == 1) return false;
	for(ll i = 2;i * i <= k; ++i){
		if(k % i == 0) return false;
	}
	return true;
}


ll ans = 0;

bool check(ll k) {
	bool ans = true;
	ans &= is_pr(k);
	while(k) {
		ans &= is_pr(k % 10);
		k/=10;
	}
	return ans;
}

int main()
{
	for(ll i = 1;i <= M; ++i) {
		if(check(i)) ans++,printf("%d\\n",i);
	}
	printf("%lld\\n",ans);
	
	return 0;
}
//ans = 1903

试题 C: 完全日期

【问题描述】

如果一个日期中年月日的各位数字之和是完全平方数,则称为一个完全日
期。
例如:2021 年 6 月 5 日的各位数字之和为 2 + 0 + 2 + 1 + 6 + 5 = 16,而
16 是一个完全平方数,它是 4 的平方。所以 2021 年 6 月 5 日是一个完全日期。
例如:2021 年 6 月 23 日的各位数字之和为 2 + 0 + 2 + 1 + 6 + 2 + 3 = 16,
是一个完全平方数。所以 2021 年 6 月 23 日也是一个完全日期。
请问,从 2001 年 1 月 1 日到 2021 年 12 月 31 日中,一共有多少个完全日
期?
##【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

解题思路

一样的是暴力跑一下,如果不放心可以手动算一下(,我跑出来是977

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<iostream>
#define ll long long
using namespace std;

int mon[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int loc_year = 2001,loc_mon = 1,loc_day = 1;
int end_year = 2021,end_mon = 12,end_day = 31;

int get(int k) {
	int ans = 0;
	while(k) {
		ans += k % 10;
		k /= 10;
	}
	return ans;
}

int main()
{
	int ans = 0;
	int op = 0;
	for(;loc_year <= end_year; ++loc_year) {
		if(loc_year % 4 == 0)   mon[2] = 29;
		else    mon[2] = 28;
		for(loc_mon = 1;loc_mon <= end_mon; ++loc_mon) {
			for(loc_day = 1;loc_day <= mon[loc_mon]; ++loc_day) {
				op++;
				int tk = get(loc_year);
				tk += get(loc_mon);
				tk += get(loc_day);
				int kkk = sqrt(tk);
				if(kkk * kkk == tk) {
					ans++;
					printf("year = %d month = %d day = %d\\n",loc_year,loc_mon,loc_day);
				}
			}
		}
	}
	printf("op == %lld, ans = %lld\\n",op,ans);
	
	return 0;
}
/*
977
*/

试题 D: 最小权值

【问题描述】

对于一棵有根二叉树 T,小蓝定义这棵树中结点的权值 W(T) 如下:
空子树的权值为 0。
如果一个结点 v 有左子树 L, 右子树 R,分别有 C(L) 和 C® 个结点,则
W(v) = 1 + 2W(L) + 3W® + (C(L)) 2 C®。
树的权值定义为树的根结点的权值。
小蓝想知道,对于一棵有 2021 个结点的二叉树,树的权值最小可能是多
少?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

解题思路

没想法,蒙了个2607074472

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<iostream>
#define ll long long
using namespace std;

ll n,k;
const int N = 2e4;
const int mod = 1e9+7;


int a[N];


ll f(ll loc) {
	if(!a[loc]) return 0;
	int k = 0;
	if(a[loc * 2]) k ++;
	if(a[loc * 2 + 1]) k++;
	return k + f(loc * 2) + f(loc * 2 + 1);
}

ll dfs(ll loc) {
	if(!a[loc]) return 0;
	int LL = f(loc * 2);
	ll ans  = 1 + 2*dfs(loc*2) + 3 * dfs(loc*2 + 1) + (LL * LL) * f(loc * 2 + 1);
	return ans;
}

int main()
{
	for(int i = 1;i <= 2021; ++i) {
		a[i] = 1;
	}
	printf("%lld\\n",dfs(1));
	return 0;
}
/*
2607074472
*/

试题 E: 大写

##【问题描述】
给定一个只包含大写字母和小写字母的字符串,请将其中所有的小写字母
转换成大写字母后将字符串输出。
##【输入格式】
输入一行包含一个字符串。
##【输出格式】
输出转换成大写后的字符串。
##【样例输入 1】
LanQiao
##【样例输出 1】
LANQIAO
##【评测用例规模与约定】
对于所有评测用例,字符串的长度不超过 100。

解题思路

直接操作即可,签到题

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<iostream>
#define ll long long
using namespace std;

string ch;

int main()
{
	cin>>ch;
	for(int i = 0;i < ch.size(); ++i) {
		if(ch[i] >= 'a' && ch[i] <= 'z') {
			ch[i] -= 'z'-'Z';
		}
	}
	cout<<ch<<endl;
	
	return 0;
}
//LanQiao

试题 F: 123

##【问题描述】
小蓝发现了一个有趣的数列,这个数列的前几项如下:
1, 1, 2, 1, 2, 3, 1, 2, 3, 4, …
小蓝发现,这个数列前 1 项是整数 1,接下来 2 项是整数 1 至 2,接下来
3 项是整数 1 至 3,接下来 4 项是整数 1 至 4,依次类推。
小蓝想知道,这个数列中,连续一段的和是多少。
##【输入格式】
输入的第一行包含一个整数 T,表示询问的个数。
接下来 T 行,每行包含一组询问,其中第 i 行包含两个整数 l i 和 r i ,表示
询问数列中第 l i 个数到第 r i 个数的和。
##【输出格式】
输出 T 行,每行包含一个整数表示对应询问的答案。
##【样例输入】
3
1 1
1 3
5 8
##【样例输出】
1
4
8
##【评测用例规模与约定】
对于 10% 的评测用例,1 ≤ T ≤ 30, 1 ≤ l i ≤ r i ≤ 100。
对于 20% 的评测用例,1 ≤ T ≤ 100, 1 ≤ l i ≤ r i ≤ 1000。
对于 40% 的评测用例,1 ≤ T ≤ 1000, 1 ≤ l i ≤ r i ≤ 10 6 。
对于 70% 的评测用例,1 ≤ T ≤ 10000, 1 ≤ l i ≤ r i ≤ 10 9 。
对于 80% 的评测用例,1 ≤ T ≤ 1000, 1 ≤ l i ≤ r i ≤ 10 12 。
对于 90% 的评测用例,1 ≤ T ≤ 10000, 1 ≤ l i ≤ r i ≤ 10 12 。
对于所有评测用例,1 ≤ T ≤ 100000, 1 ≤ l i ≤ r i ≤ 10 12 。

解题思路

找规律不难发现我们求的是等差数列求和的求和,然后看一眼数据,暴力跑一下直接T飞,所以我们可以预处理一下
,然后再将完整的那一部分求出来,最后再将不完整的求出来即可(我这个做法应该没问题?)

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<iostream>
#define ll long long
using namespace std;

ll l,r,ans;
ll len;
int t;

const int N = 1e7+10;
ll a[N];

int main()
{
	scanf("%d",&t);
	ll loc_k = 0;
	for(ll i = 1;i < N; ++i) {
		loc_k += i * (i + 1) / 2;
		a[i] = loc_k;
	}
	while(t--) {
		scanf("%lld %lld",&l,&r);
		ans = 0;
		len = (sqrt(1+8*r)-1) / 2;
		ans += a[len];
//		for(ll i = 1;i <= len; ++i) {
//			ans += i * (len - i + 1);
//		}
		len = r - (len + 1)*len/2;
		ans += (len + 1) * len/2;
		l --;
		len = (sqrt(1+8*l)-1) / 2;
		ans -= a[len];
//		for(ll i = 1;i <= len; ++i) {
//			ans -= i * (len - i + 1);
//		}
		len = l - (len+1)*len/2;
		ans -= (len+1)*len/2;
		printf("%lld\\n",ans);
	}	
	
	return 0;
}
/*
3
1 1
1 3
5 8
*/

试题 G: 异或变换

【问题描述】

小蓝有一个 01 串 s = s 1 s 2 s 3 ··· s n 。
以后每个时刻,小蓝要对这个 01 串进行一次变换。每次变换的规则相同。
对于 01 串 s = s1 s2 s3 ……sn,变换后的 01 串 s ′ = s ′1 s’2 s’3 ……s‘n为
s’1 = s1
s’2 = si-1 xor si
其中 a ⊕ b 表示两个二进制的异或,当 a 和 b 相同时结果为 0,当 a 和 b
不同时结果为 1。
请问,经过 t 次变换后的 01 串是什么?
##【输入格式】
输入的第一行包含两个整数 n, t,分别表示 01 串的长度和变换的次数。
第二行包含一个长度为 n 的 01 串。
##【输出格式】
输出一行包含一个 01 串,为变换后的串。
##【样例输入】
5 3
10110
##【样例输出】
11010

【样例说明】

初始时为 10110,变换 1 次后变为 11101,变换 2 次后变为 10011,变换 3
次后变为 11010。
【评测用例规模与约定】
对于 40% 的评测用例,1 ≤ n ≤ 100, 1 ≤ t ≤ 1000。
对于 80% 的评测用例,1 ≤ n ≤ 1000, 1 ≤ t ≤ 10 9 。
对于所有评测用例,1 ≤ n ≤ 10000, 1 ≤ t ≤ 10 18 。

解题思路

从观察得不难发现
1.小蓝的01串的第一个元素不管怎么变换,都不会发生改变
2.小兰后面n-1个元素的变化是有周期的,这个周期的长度为2(n-1)的长度
于是我们可以先把多余的周期除去再对剩余的操作数(1e4以内)进行模拟操作
详情请看代码

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<iostream>
#define ll long long
using namespace std;

ll n,t;
const int N = 1e4+10;
char ch[N];
int a[N],b[N];

int main()
{
	scanf("%lld %lld",&n,&t);
	scanf(" %s",ch);
	ll len = (n-1) * 2;
	if(t % len == 0) {
		puts(ch);
		return 0;
	}
	t %= len;
	for(int i = 0;i < n; ++i) {
		a[i] = ch[i]-'0';
	}
	b[0] = a[0];
	for(int i = 1;i <= t; ++i) {
//		printf("op times: = %d\\n",i);
		for(int j = 1;j < n; ++j) {
			b[j] = a[j] ^ a[j-1];
		}
//		for(int j = 0;j < n; ++j) {
//			printf("%d",b[j]);
//		}
//		puts("");
//		puts("---------------");
		for(int j = 1;j < n; ++j) a[j] = b[j];
	}
	for(int j = 0;j < n; ++j) {
		printf("%d",b[j]);
	}
	return 0;
}
/*
5 3
10110
*/

试题 H: 二进制问题

解题思路

这个题目,没啥想法(其实是有,但是感觉有点问题),暴力骗一下30%的分数即可

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<iostream>
#define ll long long
using namespace std;

ll n,k;
const int N = 1e4+10;
const int mod = 1e9+7;

//ll qpow(ll a,ll b) {
//	ll ans = 1;
//	while(b) {
//		if(b & 1) ans = (ans)
//	}
//}

bool check(ll key) {
	int ans = 0;
	while(key) {
		if(key%2 == 1) ans++;
		key/=2;
	}
	if(ans == k) return true;
	return false;
}

int main()
{
	scanf("%lld %lld",&n,&k);
	ll loc = 1;
	if(n > 10000000) return 0;
	for(int i = 1;i < k以上是关于第十二届蓝桥杯大赛软件赛决赛题解的主要内容,如果未能解决你的问题,请参考以下文章

第十二届蓝桥杯大赛软件赛省赛第二场题解

2021年第十二届蓝桥杯大赛软件赛决赛C/C++大学A组 个人部分题解

2021 第十二届蓝桥杯大赛软件赛省赛(第二场),C/C++大学B组题解

2021 第十二届蓝桥杯大赛软件赛省赛(第二场),C/C++大学B组题解

2021 第十二届蓝桥杯大赛软件赛省赛,C/C++ 大学B组题解

2021 第十二届蓝桥杯大赛软件赛省赛,C/C++ 大学B组题解