【题目链接】
【前置技能】
- DP
- 矩阵乘法
- AC自动机
- KMP
【题解】
- 预处理出每一位后面填 0 0 0~ 9 9 9可以走到哪一位,DP状态: f [ i ] [ j ] f[i][j] f[i][j]表示现在是第 i i i位数字,匹配到第 j j j位。转移比较显然,不多赘述。因为 n n n比较大,所以要用矩阵乘法优化转移。这里觉得AC自动机写起来比较方便,所以代码给出的是AC自动机的写法。
- 时间复杂度 O ( M 3 l o g N ) O(M^3logN) O(M3logN)
【代码】
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define MAXN 22
#define MAXLOG 30
using namespace std;
int n, m, ans, mod;
char s[MAXN];
int mat[MAXLOG + 1][MAXN][MAXN], f[1][MAXN], tmp[1][MAXN];
template <typename T> void chkmin(T &x, T y){x = min(x, y);}
template <typename T> void chkmax(T &x, T y){x = max(x, y);}
template <typename T> void read(T &x){
x = 0; int f = 1; char ch = getchar();
while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
x *= f;
}
void update(int &x, int y){
x += y;
if (x >= mod) x -= mod;
}
int mul(int x, int y){
return 1ll * x * y % mod;
}
struct AC_Automaton{
struct info{int son[10], fail, tag;}a[MAXN];
int cnt;
void ins(char *s){
int len = strlen(s + 1);
int pos = 0;
for (int i = 1; i <= len; ++i){
int ch = s[i] - '0';
if (!a[pos].son[ch]) a[pos].son[ch] = ++cnt;
pos = a[pos].son[ch];
}
a[pos].tag = 1;
}
void build(){
static int q[MAXN], l = 0, r = -1;
for (int ch = 0; ch < 10; ++ch)
if (a[0].son[ch]) q[++r] = a[0].son[ch];
while (l <= r){
int pos = q[l++];
for (int ch = 0; ch < 10; ++ch)
if (a[pos].son[ch]) {
a[a[pos].son[ch]].fail = a[a[pos].fail].son[ch];
a[a[pos].son[ch]].tag |= a[a[a[pos].son[ch]].fail].tag;
q[++r] = a[pos].son[ch];
} else a[pos].son[ch] = a[a[pos].fail].son[ch];
}
}
int go(int pos, int ch){
return a[pos].son[ch];
}
void work(){
for (int pos = 0; pos <= cnt; ++pos){
if (a[pos].tag) continue;
for (int ch = 0; ch < 10; ++ch){
int nxt = go(pos, ch);
if (a[nxt].tag) continue;
update(mat[0][pos][nxt], 1);
}
}
for (int p = 1; p <= MAXLOG; ++p)
for (int i = 0; i <= cnt; ++i)
for (int j = 0; j <= cnt; ++j)
for (int t = 0; t <= cnt; ++t)
update(mat[p][i][j], mul(mat[p - 1][i][t], mat[p - 1][t][j]));
f[0][0] = 1;
for (int p = 1; p <= MAXLOG; ++p)
if (n & (1 << p)) {
memset(tmp, 0, sizeof(tmp));
for (int i = 0; i <= 0; ++i)
for (int j = 0; j <= cnt; ++j)
for (int t = 0; t <= cnt; ++t)
update(tmp[i][j], mul(f[i][t], mat[p][t][j]));
for (int i = 0; i <= 0; ++i)
for (int j = 0; j <= cnt; ++j)
f[i][j] = tmp[i][j];
}
ans = 0;
for (int pos = 0; pos <= cnt; ++pos)
if (!a[pos].tag) update(ans, f[0][pos]);
}
}ACAM;
int main(){
read(n), read(m), read(mod);
scanf("%s", s + 1);
ACAM.ins(s);
ACAM.build();
ACAM.work();
printf("%d\n", ans);
return 0;
}