您现在的位置是:首页 >其他 >第十四届蓝桥杯大赛软件赛省赛(C/C++ 大学A组)网站首页其他

第十四届蓝桥杯大赛软件赛省赛(C/C++ 大学A组)

肖有量 2024-06-17 10:13:36
简介第十四届蓝桥杯大赛软件赛省赛(C/C++ 大学A组)

蓝桥杯 2023年省赛真题
C/C++ 大学A组


把填空挂上跟大伙对对答案,先把C/C++ B组的做了。


试题 A: 幸运数

本题总分: 5 5 5


【问题描述】

  小蓝认为如果一个数含有偶数个数位,并且前面一半的数位之和等于后面一半的数位之和,则这个数是他的幸运数字。例如 2314 2314 2314 是一个幸运数字,因为它有 4 4 4 个数位,并且 2 + 3 = 1 + 4 2 + 3 = 1 + 4 2+3=1+4。现在请你帮他计算从 1 1 1 100000000 100000000 100000000 之间共有多少个不同的幸运数字。

【答案提交】

  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


4430091


根据插板法我们可知整数 n n n拆分成 k k k个非负部分的方案数为 C n + k − 1 k − 1 C_{n+k-1}^{k-1} Cn+k1k1,有下界, j j j个部分下界为 x x x时方案数为 C n + k − 1 − j x k − 1 C_{{n+k-1-jx}}^{k-1} Cn+k1jxk1,那么根据容斥原理可知存在一个部分大于 x x x的拆分方案数为 ∑ i = 1 k ( − 1 ) i − 1 C n + i − 1 − i ( x + 1 ) i − 1 sum_{i=1}^k(-1)^{i-1}C_{n+i-1-i(x+1)}^{i-1} i=1k(1)i1Cn+i1i(x+1)i1,记 p ( n , k ) p(n,k) p(n,k)为不存在部分大于 x x x的拆分方案数,有 p ( n , k ) = C n + k − 1 k − 1 − ∑ i = 1 k ( − 1 ) i − 1 C k i C n + i − 1 − i ( x + 1 ) i − 1 = ∑ i = 0 k ( − 1 ) i C k i C n + i − 1 − i ( x + 1 ) i − 1 . p(n,k)=C_{n+k-1}^{k-1}-sum_{i=1}^k(-1)^{i-1}C_{k}^{i}C_{n+i-1-i(x+1)}^{i-1}=sum_{i=0}^k(-1)^{i}C_{k}^{i}C_{n+i-1-i(x+1)}^{i-1}. p(n,k)=Cn+k1k1i=1k(1)i1CkiCn+i1i(x+1)i1=i=0k(1)iCkiCn+i1i(x+1)i1.考虑到幸运数字数位个数为偶,即不能有前缀 0 0 0,于是考虑将 p ( n − 1 , k ) p(n-1,k) p(n1,k)看作最高位数字大于 1 1 1的方案数,但这样方案数里就包含了高位数字为 10 10 10的方案,显然不合法,所以减去不合法部分 p ( n − 10 , k − 1 ) p(n-10, k -1) p(n10,k1),最终答案为 ∑ k = 1 4 ∑ n = 1 9 k ( p ( n − 1 , k ) − p ( n − 10 , k − 1 ) ) ⋅ p ( n , k ) . sum_{k=1}^4sum_{n=1}^{9k}ig(p(n-1,k)-p(n-10,k-1)ig)cdot p(n,k). k=14n=19k(p(n1,k)p(n10,k1))p(n,k).

#include <stdio.h>

long long C(int n, int m) {
    if (m > n || n < 0) return 0;
    long long C = 1;
    for (int i = 0; i < m; ++i)
        C = C * (n - i) / (i + 1);
    return C;
}

long long p(int n, int k) {
    long long p = 0;
    for (int i = 0, sign = 1; i <= k; ++i, sign = -sign)
        p += sign * C(k, i) * C(n + k - 1 - i * 10, k - 1);
    return p;
}

int main() {
    long long ans = 0;
    for (int k = 1; k <= 4; ++k)
        for (int n = 1; n <= 9 * k; ++n)
            ans += (p(n - 1, k) - p(n - 10, k - 1)) * p(n, k);
    printf("%lld", ans);
}

优雅,永不过时

但我也数次强调过,在比赛过程中,编写这种程序的性价比是极低的,不如写个暴力程序开个线程让它自己去跑出答案。

#include <stdio.h>

int ans, buffer[9];

int main() {
    for (int k = 1; k <= 100000000; ++k) {
        int g = 0, n = 0, m = k;
        for (; m; m /= 10) buffer[n++] = m % 10;
        if (n & 1) continue;
        for (int i = 0; i < n >> 1; ++i) g += buffer[i];
        for (int i = n >> 1; i < n; ++i) g -= buffer[i];
        if (!g) ++ans;
    }
    printf("%d", ans);
}

试题 B: 有奖问答

本题总分: 5 5 5


【问题描述】

  小蓝正在参与一个现场问答的节目。活动中一共有 30 30 30 道题目,每题只有答对和答错两种情况,每答对一题得 10 10 10 分,答错一题分数归零。
  小蓝可以在任意时刻结束答题并获得目前分数对应的奖项,之后不能再答任何题目。最高奖项需要 100 100 100 分,所以到达 100 100 100 分时小蓝会直接停止答题。
  已知小蓝最终实际获得了 70 70 70 分对应的奖项,请问小蓝所有可能的答题情况有多少种?

【答案提交】

  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


8335366


d p i , j dp_{i,j} dpi,j为第 i i i个问题小蓝获得 10 j 10j 10j分的方案数,显然 d p 0 , 0 = 1 dp_{0,0}=1 dp0,0=1,对于问题 i i i,如何小蓝回答错误,那么 d p i , 0 = ∑ j = 0 9 d p i − 1 , j dp_{i,0}=sum_{j=0}^9dp_{i-1,j} dpi,0=j=09dpi1,j,因为当小明有 10 ⋅ 10 10cdot 10 1010分时问答结束故不可转移,当小明回答对时则 d p i , j = d p i − 1 , j − 1 dp_{i,j}=dp_{i-1,j-1} dpi,j=dpi1,j1,最终,答案为 ∑ i = 1 30 d p i , 7 sum_{i=1}^{30}dp_{i,7} i=130dpi,7

#include <stdio.h>

int ans = 0, dp[11] = { 1 };

int main() {
    for (int i = 1; i <= 30; ++i) {
        int loss = 0;
        for (int j = 10; j; --j) {
            loss += dp[j - 1];
            dp[j] = dp[j - 1];
        }
        dp[0] = loss;
        ans += dp[7];
    }
    printf("%d", ans);
}

做了个滚动数组,当然也可以暴搜。

#include <stdio.h>

int n = 30, ans = 0, target = 70;

void dfs(int depth, int score) {
    if (depth > n) return;
    if (score == 100) return;
    if (score == target) ++ans;
    dfs(depth + 1, score + 10);
    dfs(depth + 1, 0);
}

int main() {
    printf("%d", (dfs(0, 0), ans));
}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。