蓝桥杯 2023年省赛真题
C/C++ 大学G组
试题 A: 工作时长
试题 B: 与或异或
试题 C: 翻转
试题 D: 阶乘的和
试题 E: 公因数匹配
试题 F: 奇怪的数
试题 G: 太阳
试题 H: 子树的大小
试题 I: 高塔
试题 J: 反异或 01 串
除去第 F \rm F F 题,其他题目在其他组别都有出现过,这里就不重写了。
奇怪的数
时间限制: 1.0 s 1.0\mathrm s 1.0s 内存限制: 256.0 M B 256.0\mathrm{MB} 256.0MB 本题总分: 15 15 15 分
【问题描述】
小蓝最近在找一些奇怪的数,其奇数数位上是奇数,而偶数数位上是偶数。同时,这些数的任意
5
5
5 个连续数位的和都不大于
m
m
m。
例如当
m
=
9
m = 9
m=9 时,
10101
10101
10101 和
12303
12303
12303 就是奇怪的数,而
12345
12345
12345 和
11111
11111
11111 则不是。
小蓝想知道一共有多少个长度为
n
n
n 的上述的奇怪的数。你只需要输出答案对
998244353
998244353
998244353 取模的结果。
【输入格式】
输入一行包含两个整数 n , m n, m n,m,用一个空格分隔。
【输出格式】
输出一行包含一个整数表示答案。
【样例输入】
5 5
【样例输出】
6
【评测用例规模与约定】
对于
30
%
30\%
30% 的评测用例,
n
≤
12
n ≤ 12
n≤12;
对于
60
%
60\%
60% 的评测用例,
n
≤
5000
n ≤ 5000
n≤5000;
对于所有评测用例,
5
≤
n
≤
2
×
1
0
5
,
0
≤
m
≤
50
5 ≤ n ≤ 2 × 10^5,0 ≤ m ≤ 50
5≤n≤2×105,0≤m≤50。
动态规划
因为是要校验连续的 5 5 5 个数位上的数字之和是否大于 m m m,自然能设计出状态 f i , a , b , c , d f_{i,a,b,c,d} fi,a,b,c,d,表示第 i − 3 i-3 i−3 个数位上的数字为 a a a; i − 2 : b i-2:b i−2:b; i − 1 : c i-1:c i−1:c; i : d i:d i:d 的奇怪的数有多少个,容易找到状态转移方程: f i , a , b , c , d = ∑ f i − 1 , e , a , b , c , a + b + c + d + e ≤ m . f_{i,a,b,c,d}=\sum f_{i-1,e,a,b,c},a+b+c+d+e\leq m. fi,a,b,c,d=∑fi−1,e,a,b,c,a+b+c+d+e≤m. 转移复杂度为 O ( n D 5 ) O(nD^5) O(nD5),其中 D = 5 D=5 D=5 即每个数位可能的取值的个数,这样看来复杂度就超了, 1 s \rm 1s 1s 指定是跑不出来,于是考虑维护 f f f 在第二维的前缀和,具体地说我们记: g i , a , b , c , d = ∑ j = 0 a f i , j , b , c , d . g_{i,a,b,c,d}=\sum_{j=0}^af_{i,j,b,c,d}. gi,a,b,c,d=j=0∑afi,j,b,c,d. 则状态转移方程可改写为: g i , a , b , c , d = g i , a − 1 , b , c , d + g i − 1 , max ( 0 , min ( 9 , m − a − b − c − d ) ) , a , b , c . g_{i,a,b,c,d}=g_{i,a-1,b,c,d}+g_{i-1,\max(0,\min(9,m-a-b-c-d)),a,b,c}. gi,a,b,c,d=gi,a−1,b,c,d+gi−1,max(0,min(9,m−a−b−c−d)),a,b,c. 转移复杂度为 O ( n D 4 ) O(nD^4) O(nD4), 1 s \rm 1s 1s 有那么一点极限,标程很有可能不是动规。还有就是在实现时为了使 D = 5 D=5 D=5,转移过程会有一定的微调,具体看代码吧。文章来源:https://www.toymoban.com/news/detail-473445.html
#include <stdio.h>
const int M = 12, mod = 998244353;
int n, m, ans, g[2][M][M][M][M];
int main() {
scanf("%d %d", &n, &m);
int p = 1, q = 0;
for (int a = p; a < 10; a += 2)
for (int b = q; b < 10; b += 2)
for (int c = p; c < 10; c += 2)
for (int d = q; d < 10; d += 2) {
g[0][a + 2][b][c][d] = g[0][a][b][c][d] + (a + b + c + d <= m);
}
for (int i = 5; i <= n; ++i) {
p ^= 1, q ^= 1;
for (int a = p; a < 10; a += 2)
for (int b = q; b < 10; b += 2)
for (int c = p; c < 10; c += 2)
for (int d = q; d < 10; d += 2) {
int f = m - a - b - c - d;
if (q != (f & 1)) --f;
if (f > 8 + p) f = 8 + q;
g[i & 1][a + 2][b][c][d] = (g[i & 1][a][b][c][d] + (f < q ? 0 : g[~i & 1][f + 2][a][b][c])) % mod;
}
}
for (int b = q; b < 10; b += 2)
for (int c = p; c < 10; c += 2)
for (int d = q; d < 10; d += 2) {
int f = m - b - c - d;
if (f < p) continue;
if (p != (f & 1)) --f;
if (f > 8 + p) f = 8 + p;
ans = (ans + g[n & 1][f + 2][b][c][d]) % mod;
}
printf("%d", ans);
}
输入200000 50
,
4000
4000
4000 系
R
y
z
e
n
\rm Ryzen
Ryzen 刚好在
1
s
\rm 1s
1s 跑完,这放在评测机上不开
O
\rm\small O
O
2
2
2 就超时了。推了半天式子也没什么结果,不过有一种实在的优化方案是:
记一个长度为
4
4
4 奇偶交替数
n
n
n 为
a
b
c
d
abcd
abcd,它的数位之和为
s
=
a
+
b
+
c
+
d
s=a+b+c+d
s=a+b+c+d,我们记
n
n
n 的逆
n
′
=
(
9
−
a
)
(
9
−
b
)
(
9
−
c
)
(
9
−
d
)
n'=(9-a)(9-b)(9-c)(9-d)
n′=(9−a)(9−b)(9−c)(9−d) ,则逆的数位之和为
s
′
=
36
−
s
s'=36-s
s′=36−s,显然
n
n
n 的全集的按数位之和划分,它的大小以
18
18
18 为中点对称。如果输入的
m
m
m 在对称点以左,我们按原问题求解,在对称点及对称点以右我们求其逆问题,即一个数
S
S
S,为长度为
n
n
n 且存在连续
5
5
5 个数位之和大于
m
m
m 的数的个数,此时答案为
5
n
−
S
5^n-S
5n−S,这样下来状态转移的次数减少一半,可以在时间限制内计算出答案。
不过相应的代码量翻倍,没这个必要,还是题太臭了。文章来源地址https://www.toymoban.com/news/detail-473445.html
到了这里,关于第十四届蓝桥杯大赛软件赛省赛(C/C++ 研究生组)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!