bzoj 1009
[HNOI2008]GT考试
Description
阿申准备报名参加GT
考试,
准考证号为 位数 , 他不希望准考证号上出现不吉利的数字。
他的不吉利数学
有 位,
不出现是指 中没有恰好一段等于 .
和 可以为 .
Input
第一行输入 . 接下来一行输入 位的数. .
Output
阿申想知道不出现不吉利数字的号码有多少种,输出模 取余的结果.
Sample Input
4 3 100
111
Sample Output
81
题解
设 表示考虑到第 位,其后缀最大能匹配到不吉利数字前面 位的方案数. 则有
式中 的意义是 加上一个字符后其后缀是 的方案数.
边界条件 .
显然这可以用矩阵快速幂加速,最后答案就是 .
现在考虑怎么求出系数 . 初始令所有的 .
我们用 KMP
处理出串 的失配函数 ,遍历每一位 ,
枚举添加的字符 ,然后令 ,如果 ,
则令 直到 或者 .
接着如果 ,
则表示在 后添加一个字符 的话,
是这个串的一个后缀,且是最长的一个是 的一个前缀的后缀,
也就是说状态 可以转移到 ,于是我们令 加上 .
否则必有 ,就是说 添加字符 后,
没有后缀是 的一个前缀,那么状态 也就转移到了 ,
令 加 即可.
代码
#include <cstdio>
using namespace std;
int k;
inline void add(int &dest, int delta)
{
dest += delta;
if (dest < 0) dest += k;
if (dest >= k) dest -= k;
}
inline void mul(int &dest, int times)
{
dest *= times;
dest -= dest / k * k;
}
inline int rmul(int a, int b)
{
int z = a * b;
return z - z / k * k;
}
int M;
#define MATSZ (1 << 5)
/* dest = b * dest */
void matmul(int dest[MATSZ][MATSZ], int b[MATSZ][MATSZ])
{
int tmp[MATSZ][MATSZ] = {{0}};
for (int i = 0; i < M; i++)
for (int j = 0; j < M; j++)
for (int l = 0; l < M; l++)
add(tmp[i][j], rmul(b[i][l], dest[l][j]));
for (int i = 0; i < M; i++)
for (int j = 0; j < M; j++)
dest[i][j] = tmp[i][j];
}
char A[MATSZ];
int f[MATSZ];
int trans[MATSZ][MATSZ];
void calc_transMAT(void)
{
int i, j;
f[1] = j = 0;
for (i = 2; i <= M; i++)
{
while (j && A[i] != A[j + 1]) j = f[j];
if (A[i] == A[j + 1]) j++;
f[i] = j;
}
for (i = 0; i < M; i++)
for (j = '0'; j <= '9'; j++)
{
int l = i;
while (l && A[l + 1] != j) l = f[l];
if (A[l + 1] == j) l++;
/* i -> l is possible */
if (l < M) add(trans[l][i], 1);
}
}
int dp[MATSZ][MATSZ];
int main(void)
{
int n;
scanf("%d%d%d", &n, &M, &k);
scanf("%s", A + 1);
calc_transMAT();
dp[0][0] = 1;
while (n)
{
if (1 & n) matmul(dp, trans);
matmul(trans, trans);
n >>= 1;
}
int ans = 0;
for (int i = 0; i < M; i++)
add(ans, dp[i][0]);
printf("%d\n", ans);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84