蓝桥杯 2021年省赛真题 (C/C++ 大学C组 )
解析移步对应 Java组 的题解。
#A ASC
本题总分: 5 5 5 分
问题描述
已知大写字母 A A A 的 A S C I I \mathrm{ASCII} ASCII 码为 65 65 65,请问大写字母 L L L 的 A S C I I \mathrm{ASCII} ASCII 码是多少?
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
76
calcCode:
#include <stdio.h>
int main() {
// printf("%d", 65 + 'L' - 'A');
printf("%d", 'L');
}
#B 空间
本题总分: 5 5 5 分
问题描述
小蓝准备用 256 M B 256\mathrm{MB} 256MB 的内存空间开一个数组,数组的每个元素都是 32 32 32 位二进制整数,如果不考虑程序占用的空间和维护内存需要的辅助空间,请问 256 M B 256\mathrm{MB} 256MB 的空间可以存储多少个 32 32 32 位二进制整数?
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
67108864
calcCode:
#include <stdio.h>
int main() {
printf("%d", 256 >> 2 << 20);
}
checkCode:
#include <stdio.h>
#include <math.h>
int A[67108864];
int main() {
printf("%f", sizeof A / pow(2, 20));
}
虽然 sizeof
是在编译阶段进行的,
从这个意义上看并不是什么非要支持不可的函数。
但 C \mathrm{C} C,行!
#C 卡片
本题总分: 10 10 10 分
问题描述
小蓝有很多数字卡片,每张卡片上都是数字 0 0 0 到 9 9 9。
小蓝准备用这些卡片来拼一些数,他想从 1 1 1 开始拼出正整数,每拼一个,就保存起来,卡片就不能用来拼其它数了。
小蓝想知道自己能从 1 1 1 拼到多少。
例如,当小蓝有 30 30 30 张卡片,其中 0 0 0 到 9 9 9 各 3 3 3 张,则小蓝可以拼出 1 1 1 到 10 10 10,但是拼 11 11 11 时卡片 1 1 1 已经只有一张了,不够拼出 11 11 11。
现在小蓝手里有 0 0 0 到 9 9 9 的卡片各 2021 2021 2021 张,共 20210 20210 20210 张,请问小蓝可以从 1 1 1 拼到多少?
提示:建议使用计算机编程解决问题。
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
3181
calcCode:
#include <stdio.h>
int n, ans, cnt;
int main() {
while (1) {
n = ans;
while (n) {
if (n % 10 == 1) cnt++;
n /= 10;
}
if (cnt < 2021) ans++;
else break;
}
printf("%d", ans);
}
#D 相乘
本题总分: 10 10 10 分
问题描述
小蓝发现,他将 1 1 1 至 1000000007 1000000007 1000000007 之间的不同的数与 2021 2021 2021 相乘后再求除以 1000000007 1000000007 1000000007 的余数,会得到不同的数。
小蓝想知道,能不能在 1 1 1 至 1000000007 1000000007 1000000007 之间找到一个数,与 2021 2021 2021 相乘后再除以 1000000007 1000000007 1000000007 后的余数为 999999999 999999999 999999999。如果存在,请在答案中提交这个数;
如果不存在,请在答案中提交 0 0 0。
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
17812964
calcCode:
#include <iostream>
int x, y, a = 2021, b = 999999999, p = 1000000007;
int exgcd(int a, int b, int &x, int &y) {
if (b == 0) {
x = 1; y = 0;
return a;
}
int d = exgcd(b, a % b, y, x), z = x;
y -= a / b * x;
return d;
}
int main() {
int d = exgcd(a, p, x, y);
std::cout << (long long)x * b / d % p;
}
#E 路径
本题总分: 15 15 15 分
问题描述
小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图中的最短路径。
小蓝的图由 2021 2021 2021 个结点组成,依次编号 1 1 1 至 2021 2021 2021。对于两个不同的结点 a , b a, b a,b,如果 a a a 和 b b b 的差的绝对值大于 21 21 21,则两个结点之间没有边相连;如果 a a a 和 b b b 的差的绝对值小于等于 21 21 21,则两个点之间有一条长度为 a a a 和 b b b 的最小公倍数的无向边相连。
例如:结点 1 1 1 和结点 23 23 23 之间没有边相连;结点 3 3 3 和结点 24 24 24 之间有一条无向边,长度为 24 24 24;结点 15 15 15 和结点 25 25 25 之间有一条无向边,长度为 75 75 75。
请计算,结点 1 1 1 和结点 2021 2021 2021 之间的最短路径长度是多少。
提示:建议使用计算机编程解决问题。
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
10266837
calcCode:
#include <stdio.h>
#include <string.h>
const int N = 2021;
int map[N + 1][N + 1];
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a; }
int lcm(int a, int b) {
return a * b / gcd(a, b); }
int min(int a, int b) {
return a < b ? a : b; }
int main() {
memset(&map, 0x3F, sizeof map);
for (int u = 1; u <= N; u++)
for (int v = min(N, u + 21); v > u; --v)
map[u][v] = map[v][u] = lcm(u, v);
for (int k = 1; k <= N; k++)
for (int i = 1; i <= N; i++)
for (int j = 1; j <= N; j++)
map[i][j] = min(map[i][j], map[i][k] + map[k][j]);
printf("%d", map[1][N]);
}
#F 时间显示
时间限制: 1.0 s 1.0\mathrm s 1.0s 内存限制: 256.0 M B 256.0\mathrm{MB} 256.0MB 本题总分: 15 15 15 分
问题描述
小蓝要和朋友合作开发一个时间显示的网站。在服务器上,朋友已经获取了当前的时间,用一个整数表示,值为从 1970 1970 1970 年 1 1 1 月 1 日 00 : 00 : 00 00:00:00 00:00:00 到当前时刻经过的毫秒数。
现在,小蓝要在客户端显示出这个时间。小蓝不用显示出年月日,只需显示出时分秒即可,毫秒也不用显示,直接舍去即可。
给定一个用整数表示的时间,请将这个时间对应的时分秒输出。
输入格式
输入一行包含一个整数,表示时间。
输出格式
输出时分秒表示的当前时间,格式形如 H H HH HH: M M MM MM: S S SS SS,其中 H H HH HH 表示时,值为 0 0 0 到 23 23 23, M M MM MM 表示分,值为 0 0 0 到 59 59 59, S S SS SS 表示秒,值为 0 0 0 到 59 59 59。时、分、秒不足两位时补前导 0 0 0。
测试样例1
Input:
46800999
Output:
13:00:00
测试样例2
Input:
1618708103123
Output:
01:08:23
评测用例规模与约定
对于所有评测用例,给定的时间为不超过 1 0 18 10^{18} 1018 的正整数。
#include <stdio.h>
int main() {
long long n;
scanf("%lld", &n);
printf("%02d:%02d:%02d", n / 1000 / 60 / 60 % 24, n / 1000 / 60 % 60, n / 1000 % 60);
}
#G 最少砝码
时间限制: 1.0 s 1.0\mathrm s 1.0s 内存限制: 256.0 M B 256.0\mathrm{MB} 256.0MB 本题总分: 20 20 20 分
问题描述
你有一架天平。现在你要设计一套砝码,使得利用这些砝码可以称出任意小于等于 N N N 的正整数重量。
那么这套砝码最少需要包含多少个砝码?
注意砝码可以放在天平两边。
输入格式
输入包含一个正整数 N N N。
输出格式
输出一个整数代表答案。
测试样例1
Input:
7
Output:
3
Explanation:
3 个砝码重量是 1、4、6,可以称出 1 至 7 的所有重量。
1 = 1;
2 = 6 − 4 (天平一边放 6,另一边放 4);
3 = 4 − 1;
4 = 4;
5 = 6 − 1;
6 = 6;
7 = 1 + 6;
少于 3 个砝码不可能称出 1 至 7 的所有重量。
评测用例规模与约定
对于所有评测用例, 1 ≤ N ≤ 1000000000 1 ≤ N ≤ 1000000000 1≤N≤1000000000。
#include <stdio.h>
int main() {
long long n, ans = 1;
scanf("%lld", &n);
for (long long i = 1; i < n; i = i * 3 + 1, ans++);
printf("%d", ans);
}
#H 杨辉三角形
时间限制: 1.0 s 1.0\mathrm s 1.0s 内存限制: 256.0 M B 256.0\mathrm{MB} 256.0MB 本题总分: 20 20 20 分
下面的图形是著名的杨辉三角形:
如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列:
1 , 1 , 1 , 1 , 2 , 1 , 1 , 3 , 3 , 1 , 1 , 4 , 6 , 4 , 1 , ⋯ 1, 1, 1, 1, 2, 1, 1, 3, 3, 1, 1, 4, 6, 4, 1, \cdots 1,1,1,1,2,1,1,3,3,1,1,4,6,4,1,⋯
给定一个正整数 N N N,请你输出数列中第一次出现 N N N 是在第几个数?
输入格式
输入一个整数 N N N。
输出格式
输出一个整数代表答案。
测试样例1
Input:
6
Output:
13
评测用例规模与约定
对于 20 20 20% 的评测用例, 1 ≤ N ≤ 10 1 ≤ N ≤ 10 1≤N≤10;
对于所有评测用例, 1 ≤ N ≤ 1000000000 1 ≤ N ≤ 1000000000 1≤N≤1000000000。
#include <stdio.h>
typedef long long ll;
ll N, ans = 1;
ll min(ll a, ll b) {
return a < b ? a : b; }
ll C(int n, int m) {
ll C = 1;
for (int i = 0; i < m; i++) {
C = C * (n - i) / (i + 1);
if (C > N) return C;
}
return C;
}
int main() {
scanf("%lld", &N);
if (N > 1) {
ans = N * (N + 1) / 2 + 2;
for (int m = 2; m < 16; m++) {
int start = m << 1, end = N;
while (start <= end) {
int n = start + end >> 1;
if (C(n, m) == N) {
ans = min(ans, (n + 1ll) * n / 2 + m + 1);
break;
}
if (C(n, m) > N) end = n - 1;
else start = n + 1;
}
}
}
printf("%lld", ans);
}
#I 左孩子右兄弟
时间限制: 1.0 s 1.0\mathrm s 1.0s 内存限制: 256.0 M B 256.0\mathrm{MB} 256.0MB 本题总分: 25 25 25 分
问题描述
对于一棵多叉树,我们可以通过 “左孩子右兄弟” 表示法,将其转化成一棵二叉树。
如果我们认为每个结点的子结点是无序的,那么得到的二叉树可能不唯一。换句话说,每个结点可以选任意子结点作为左孩子,并按任意顺序连接右兄弟。
给定一棵包含 N N N 个结点的多叉树,结点从 1 1 1 至 N N N 编号,其中 1 1 1 号结点是根,每个结点的父结点的编号比自己的编号小。请你计算其通过 “左孩子右兄弟” 表示法转化成的二叉树,高度最高是多少。注:只有根结点这一个结点的树高度为 0 0 0 。
例如如下的多叉树:
可能有以下 3 3 3 种 (这里只列出 3 3 3 种,并不是全部) 不同的 “左孩子右兄弟”表示:
其中最后一种高度最高,为 4 4 4。
输入格式
输入的第一行包含一个整数 N N N。
以下 N − 1 N −1 N−1 行,每行包含一个整数,依次表示 2 2 2 至 N N N 号结点的父结点编号。
输出格式
输出一个整数表示答案。
测试样例1
Input:
5
1
1
1
2
Output:
4
评测用例规模与约定
对于 30 30 30% 的评测用例, 1 ≤ N ≤ 20 1 ≤ N ≤ 20 1≤N≤20;
对于所有评测用例, 1 ≤ N ≤ 100000 1 ≤ N ≤ 100000 1≤N≤100000。
#include <bits/stdc++.h>
using namespace std;
#define N 100005
vector<int> tree[N];
int dp(int root) {
if (!tree[root].size()) return 0;
int res = 0;
for (int son : tree[root])
res = max(res, dp(son));
return res + tree[root].size();
}
int main() {
int n, t;
cin >> n;
for (int i = 2; i <= n; ++i)
cin >> t, tree[t].push_back(i);
cout << dp(1) << endl;
}
#J 括号序列
时间限制: 1.0 s 1.0\mathrm s 1.0s 内存限制: 256.0 M B 256.0\mathrm{MB} 256.0MB 本题总分: 25 25 25 分
问题描述
给定一个括号序列,要求尽可能少地添加若干括号使得括号序列变得合法,当添加完成后,会产生不同的添加结果,请问有多少种本质不同的添加结果。
两个结果是本质不同的是指存在某个位置一个结果是左括号,而另一个是右括号。
例如,对于括号序列 (((),只需要添加两个括号就能让其合法,有以下几种不同的添加结果:()()()、()(())、(())()、(()()) 和 ((()))。
输入格式
输入一行包含一个字符串 s s s,表示给定的括号序列,序列中只有左括号和右括号。
输出格式
输出一个整数表示答案,答案可能很大,请输出答案除以 1000000007 1000000007 1000000007 (即 1 0 9 + 7 10^{9} + 7 109+7) 的余数。
测试样例1
Input:
((()
Output:
5
评测用例规模与约定
对于 40 40 40% 的评测用例, ∣ s ∣ ≤ 200 |s| ≤ 200 ∣s∣≤200。
对于所有评测用例, 1 ≤ ∣ s ∣ ≤ 5000 1 ≤ |s| ≤ 5000 1≤∣s∣≤5000。
#include <stdio.h>
#include <string.h>
typedef long long ll;
#define N 5555
int dp[N][N], p = 1000000007;
char str[N] = {
'$'};
int calc(char *str) {
memset(dp, 0, sizeof dp);
dp[0][0] = 1;
int opening = 0, n = strlen(str) - 1;
for (int i = 1; i <= n; i++) {
if (str[i] == '(') {
for (int j = 1; j <= n; j++)
dp[i][j] = dp[i - 1][j - 1];
opening++;
}
else {
dp[i][0] = (dp[i - 1][0] + dp[i - 1][1]) % p;
for (int j = 1; j <= n; j++)
dp[i][j] = (dp[i][j - 1] + dp[i - 1][j + 1]) % p;
if (opening) opening--;
}
}
return dp[n][opening];
}
int reverse(char *str) {
for (int i = 1, j = strlen(str) - 1; i <= j; i++, j--) {
char temp = str[i] ^ 1;
str[i] = str[j] ^ 1;
str[j] = temp;
}
}
int main() {
scanf("%s", str + 1);
ll ans = calc(str);
reverse(str);
printf("%d\n", ans * calc(str) % p);
}