您现在的位置是:首页 >其他 >第十四届蓝桥杯大赛软件赛省赛(C/C++ 大学A组)网站首页其他
第十四届蓝桥杯大赛软件赛省赛(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+k−1k−1,有下界, j j j个部分下界为 x x x时方案数为 C n + k − 1 − j x k − 1 C_{{n+k-1-jx}}^{k-1} Cn+k−1−jxk−1,那么根据容斥原理可知存在一个部分大于 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)i−1Cn+i−1−i(x+1)i−1,记 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+k−1k−1−i=1∑k(−1)i−1CkiCn+i−1−i(x+1)i−1=i=0∑k(−1)iCkiCn+i−1−i(x+1)i−1.考虑到幸运数字数位个数为偶,即不能有前缀 0 0 0,于是考虑将 p ( n − 1 , k ) p(n-1,k) p(n−1,k)看作最高位数字大于 1 1 1的方案数,但这样方案数里就包含了高位数字为 10 10 10的方案,显然不合法,所以减去不合法部分 p ( n − 10 , k − 1 ) p(n-10, k -1) p(n−10,k−1),最终答案为 ∑ 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=1∑4n=1∑9k(p(n−1,k)−p(n−10,k−1))⋅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=09dpi−1,j,因为当小明有 10 ⋅ 10 10cdot 10 10⋅10分时问答结束故不可转移,当小明回答对时则 d p i , j = d p i − 1 , j − 1 dp_{i,j}=dp_{i-1,j-1} dpi,j=dpi−1,j−1,最终,答案为 ∑ 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));
}