题意:
给出一个由
{
′
0
′
∼
′
9
′
、
′
?
′
}
\{'0'\sim'9'、'?'\}
{′0′∼′9′、′?′}构成的字符串,将字符串中的每个
?
?
? 都用
′
0
′
∼
′
9
′
'0'\sim'9'
′0′∼′9′ 代替,然后将得到的整数对
13
13
13 取模,问有多少个构成的整数取余后值为
5
5
5
思路:
一道比较裸的线性
d
p
dp
dp,可能有人没有了解过同余定理,那先补充一下:
- 和的取余等于取余的和的取余—— ( a + b ) % m o d = ( a % m o d + b % m o d ) % m o d (a + b) \% mod = (a \% mod + b \% mod) \% mod (a+b)%mod=(a%mod+b%mod)%mod
- 乘积的取余等于取余的乘积取余—— ( a ∗ b ) % m o d = ( ( a % m o d ) ∗ ( b % m o d ) ) % m o d (a * b) \% mod = ((a \% mod) * (b \% mod)) \% mod (a∗b)%mod=((a%mod)∗(b%mod))%mod
那么接下来就好说多了,首先是状态表示:
f
[
i
]
[
j
]
f[i][j]
f[i][j] 为字符串从前往后到第
i
i
i 位为止,转化为的整数对
13
13
13 取模得
j
j
j 的情况有多少种
然后是状态计算:
如果第
i
i
i 位为数字的话,那么就用
f
[
i
−
1
]
[
j
]
f[i - 1][j]
f[i−1][j] 去更新
f
[
i
]
[
(
j
∗
10
+
s
[
i
]
)
%
13
]
(
0
≤
j
≤
12
)
f[i][(j*10+s[i])\%13](0\leq j\leq12)
f[i][(j∗10+s[i])%13](0≤j≤12)
如果第
i
i
i 位是
?
?
? 的话,其实道理也一样,因为它有可能是
′
0
′
∼
′
9
′
'0'\sim'9'
′0′∼′9′ ,那就全部都过一遍就好了
时间复杂度: O ( n ) O(n) O(n)
#include <bits/stdc++.h>
using namespace std;
#define sf(x) scanf("%d",&x)
const int N = 2e5 + 10, mod = 1e9 + 7;
int f[N][13];
char s[N];
int main() {
scanf("%s", s + 1);
f[0][0] = 1;
int len = strlen(s + 1);
for (int i = 1; i <= len; i++)
if (s[i] == '?') {
for (int k = 0; k <= 9; k++)
for (int j = 0; j < 13; j++)
f[i][(j * 10 + k) % 13] = (f[i][(j * 10 + k) % 13] + f[i - 1][j]) % mod;
} else {
int k = s[i] - '0';
for (int j = 0; j < 13; j++)
f[i][(j * 10 + k) % 13] = (f[i][(j * 10 + k) % 13] + f[i - 1][j]) % mod;
}
cout << f[len][5];
return 0;
}