f[i][j]表示前i位准考证号,匹配到了不吉利串第j位。我们考虑如何将f[i][j]转移到f[i+1][j].首先用kmp处理出fail数组,假设现在在做前i位匹配到了第j位,那么对于i+1位可能出现的每个字符我们都从j开始匹配,看能转移到哪里去。就是这样:
f[0][0]=1;
for(int i=0;i<=n;i++){
for(int j=0;j<m;j++){
for(int ch='0';ch<='9';ch++){
int k=j;
while(k>0&&s[k+1]!=ch) k=fail[k];
if(s[k+1]==ch) k++;
if(k!=m) f[i+1][k]+=f[i][j];
}
}
}
然而n=10e9,显然会T,况且也存不下。。所以我们考虑矩阵倍增,如果现在匹配到了第i位,我们可能转移到第k位,则矩阵[i][k]++;至于怎么转移,跟上面一样。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 25
#define ll long long
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n,m,mod,fail[N],ans=0;
char s[N];
inline void getfail(){
int k=0;fail[1]=0;
for(int i=2;i<=m;++i){
while(k&&s[k+1]!=s[i]) k=fail[k];
if(s[k+1]==s[i]) ++k;
fail[i]=k;
}
}
struct matrix{
int mat[N][N];
matrix(bool t){
memset(mat,0,sizeof(mat));
if(t) for(int i=0;i<m;++i) mat[i][i]=1;
}
matrix operator*(matrix x){
matrix res(0);
for(int i=0;i<m;++i)
for(int j=0;j<m;++j)
for(int k=0;k<m;++k)
res.mat[i][j]=(res.mat[i][j]+(ll)mat[i][k]*x.mat[k][j])%mod;
return res;
}
matrix operator^(int k){
matrix res(1),b(0);memcpy(b.mat,mat,sizeof(mat));
for(;k;k>>=1,b=b*b)
if(k&1) res=res*b;
return res;
}
}base(0),a(0);
int main(){
// freopen("a.in","r",stdin);
n=read();m=read();mod=read();
scanf("%s",s+1);
getfail();
for(int i=0;i<m;++i){
for(int ch='0';ch<='9';++ch){
int k=i;
while(k&&s[k+1]!=ch) k=fail[k];
if(s[k+1]==ch) ++k;
if(k!=m) base.mat[i][k]++;
}
}
a.mat[0][0]=1;
a=a*(base^n);
for(int i=0;i<m;++i) ans=(ans+a.mat[0][i])%mod;
printf("%d\n",ans);
return 0;
}