阿申准备报名参加 GT 考试,准考证号为 nn位数 X1X2Xn(0Xi9)X_1X_2\cdots X_n(0\le X_i\le 9),他不希望准考证号上出现不吉利的数字。

他的不吉利数字 A1A2Am(0Ai9)A_1A_2\cdots A_m(0\le A_i\le 9)mm位,不出现是指 X1X2XnX_1X_2\cdots X_n中没有恰好一段等于A1A2AmA_1A_2\cdots A_m

给出AA,求XX可能的方案数

n109,m20,K1000n\le10^9, m\le20, K\le 1000

LOJ 10224

Solution

f[i][j]f[i][j]表示长度为ii的串,最后jj个可以匹配模板串前jj位的方案数,答案为i=0m1f[n][i]\sum_{i=0}^{m-1}f[n][i]

转移ff的话可以考虑设g[i][j]g[i][j]表示模板串从前缀ii失配后转移到前缀jj的方案数,这个可以通过枚举下一个字符,然后用kmpnextnext直接暴力算

那么f[i+1][k]=j=1mf[i][j]g[j][k]f[i + 1][k] = \sum_{j=1}^{m}f[i][j]* g[j][k],矩阵快速幂优化即可

Code

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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <bits/stdc++.h>

#define x first
#define y second
#define y1 Y1
#define y2 Y2
#define mp make_pair
#define pb push_back

using namespace std;

typedef long long LL;
typedef pair <int, int> pii;

template <typename T> inline int Chkmax (T &a, T b) { return a < b ? a = b, 1 : 0; }
template <typename T> inline int Chkmin (T &a, T b) { return a > b ? a = b, 1 : 0; }
template <typename T> inline T read ()
{
T sum = 0, fl = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fl = -1;
for (; isdigit(ch); ch = getchar()) sum = (sum << 3) + (sum << 1) + ch - '0';
return sum * fl;
}

inline void proc_status ()
{
ifstream t ("/proc/self/status");
cerr << string (istreambuf_iterator <char> (t), istreambuf_iterator <char> ()) << endl;
}

const int Maxn = 20 + 5;

int N, M, Mod;
int Next[Maxn];
int A[Maxn];

inline void Add (int &a, int b) { if ((a += b) >= Mod) a -= Mod; }

struct Matrix
{
int A[Maxn][Maxn];
inline int* operator [] (const int &x) { return A[x]; }

inline void init ()
{
for (int i = 0; i < M; ++i)
for (int j = 0; j < M; ++j)
{
A[i][j] = 0;
if (i == j) A[i][j] = 1;
}
}

inline Matrix operator * (const Matrix &rhs) const
{
Matrix ans;
for (int i = 0; i < M; ++i)
for (int j = 0; j < M; ++j)
{
ans[i][j] = 0;
for (int k = 0; k < M; ++k)
Add (ans[i][j], (LL)A[i][k] * rhs.A[k][j] % Mod);
}
return ans;
}

} trans;

inline Matrix Pow (Matrix a, int b)
{
Matrix ans; ans.init();
for (int i = b; i; i >>= 1, a = a * a) if (i & 1) ans = ans * a;
return ans;
}

inline void Init ()
{
int j = 0;
for (int i = 2; i <= M; ++i)
{
while (j && A[j + 1] != A[i]) j = Next[j];
if (A[j + 1] == A[i]) ++j;
Next[i] = j;
}

for (int i = 0; i < M; ++i)
{
for (int j = 0; j <= 9; ++j)
{
int k = i;
while (k && A[k + 1] != j) k = Next[k];
if (A[k + 1] == j) ++k;
++trans[i][k];
}
}
}

inline void Solve ()
{
Init ();
Matrix res = Pow (trans, N);

int ans = 0;
for (int i = 0; i < M; ++i) Add (ans, res[0][i]);
cout << ans << endl;
}

inline void Input ()
{
N = read<int>(), M = read<int>(), Mod = read<int>();
char S[Maxn];
scanf("%s", S + 1);
for (int i = 1; i <= M; ++i) A[i] = S[i] - '0';
A[0] = 2003;
A[M + 1] = 216;
}

int main()
{

#ifndef ONLINE_JUDGE
freopen("A.in", "r", stdin);
freopen("A.out", "w", stdout);
#endif

Input ();
Solve ();

return 0;
}