第十二届蓝桥杯 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 1N1000000000


#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 1N10
  对于所有评测用例, 1 ≤ N ≤ 1000000000 1 ≤ N ≤ 1000000000 1N1000000000


#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 N1 行,每行包含一个整数,依次表示 2 2 2 N N N 号结点的父结点编号。


输出格式

  输出一个整数表示答案。


测试样例1

Input:
5
1
1
1
2

Output:
4

评测用例规模与约定

  对于 30 30 30% 的评测用例, 1 ≤ N ≤ 20 1 ≤ N ≤ 20 1N20
  对于所有评测用例, 1 ≤ N ≤ 100000 1 ≤ N ≤ 100000 1N100000


#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 s200
  对于所有评测用例, 1 ≤ ∣ s ∣ ≤ 5000 1 ≤ |s| ≤ 5000 1s5000


#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);
}

猜你喜欢

转载自blog.csdn.net/qq_43449564/article/details/123435018