题解:
一开始看觉得很难,理解了之后其实还挺容易的。
首先我们考虑朴素DP:
令f[i][j]表示长串到了第i项, 与不吉利数字(模式串)匹配到了第j项的方案。
显然ans = f[n][0] + f[n][1] + …… + f[n][m-1];
可以肉眼看出f[1][0] = 9, f[1][1] = 1;
于是我们考虑如何转移。
首先我们观察到,f[i-1][j]如果要给f[i][k]做贡献,那么就要使得匹配到j位变成匹配到k位。
我们设g[j][k]表示原本是匹配到j位,加入一个新数字后变成匹配到k位的方案数。这里的匹配到x位的x是指匹配到模式串的第x位。
那么我们有转移方程:$f[i][j] = sum_{i=0}^{m-1}f[i-1][k]*g[k][j]$
那么如何求解g[i][j]呢?
可以考虑KMP。但是由于数据比较小,所以这里就直接用暴力了。
首先我们枚举i表示当前已经匹配到了第i位(i可以为0)
然后我们枚举新加进来的数
再我们再枚举可能会匹配 l 位,从高位开始枚举,
然后暴力检验看是不是可以刚好匹配到 l 位,注意要从后面开始匹配,如果没解释清楚,看代码就知道了。
如果可以刚好匹配到 l 位,那么我们就++g[i][l]并break
然后我们考虑优化:
观察转移方程$f[i][k] = sum_{i=0}^{m-1}f[i-1][j]*g[j][k]$.
emmmm,..与矩阵相乘完美吻合。。。。
所以用矩阵加速一下就好啦
1 #include<bits/stdc++.h>
2 using namespace std;
3 #define R register int
4 #define AC 23
5 int n, m, p, ans;
6 char s[AC], tmp[AC];
7 struct matrix{
8 int s[AC][AC];
9 }f, g, box;
10
11 void pre()
12 {
13 scanf("%d%d%d", &n, &m, &p);
14 scanf("%s", s + 1);
15 if(n == 1)
16 {
17 if(m == 1) ans = 9;
18 else ans = 10;
19 ans %= p;
20 printf("%d
", ans);
21 exit(0);
22 }
23 //g.s[0][1] = 1, g.s[0][0] = 9;//因为g是匹配数,所以行也可能是0
24 for(R i = 0; i < m ; i++)//枚举已经匹配到了哪一位
25 {
26 tmp[i] = s[i];
27 for(R j = 0; j <= 9; j++)//枚举下一位是什么
28 {
29 tmp[i + 1] = j + '0';
30 int t, k = 0;
31 for(R l = i + 1; l >= 0; l--)//枚举最多可以匹配几位
32 {
33 t = l, k = i + 1;
34 while(s[t] == tmp[k] && t) --t, --k;
35 if(!t)
36 {
37 if(l != m) ++g.s[i][l];
38 break;
39 }
40
41 }
42 }
43 }
44 }
45
46 void build()
47 {
48 f.s[1][1] = 1, f.s[1][0] = 9;
49 }
50
51 void cal1()
52 {
53 for(R j = 0; j < m; j++)//枚举是第一行的第几列,注意0也是合法的
54 {
55 box.s[1][j] = 0;
56 for(R l = 0; l < m; l++)//枚举f的对应行和g的对应列
57 box.s[1][j] += f.s[1][l] * g.s[l][j];
58 box.s[1][j] %= p;
59 }
60 f = box;
61 }
62
63 void cal2()
64 {
65 for(R i = 0; i < m; i++)
66 for(R j = 0; j < m; j++)
67 {
68 box.s[i][j] = 0;
69 for(R l = 0; l < m; l++)
70 box.s[i][j] += g.s[i][l] * g.s[l][j];
71 box.s[i][j] %= p;
72 }
73 g = box;
74 }
75
76 void qpow(int have)
77 {
78 while(have)
79 {
80 if(have & 1) cal1();
81 cal2();
82 have >>= 1;
83 }
84 }
85
86 void work()
87 {
88 for(R i = 0; i < m; i++) ans += f.s[1][i];
89 ans %= p;
90 printf("%d
", ans);
91 }
92
93 int main()
94 {
95 freopen("in.in", "r", stdin);
96 pre();
97 build();
98 qpow(n - 1);
99 work();
100 fclose(stdin);
101 return 0;
102 }