【解题思路】
先KMP出fail数组,再用fail数组求出M[i][j],表示上一次匹配到第i位,这次可以遇到多少种不同的字符,使之转而匹配到第j位。
设集合S=[1,m]∩N
又设f[i][j]表示共读入了i个字符,当前匹配到了第j位时,有多少种情况。有转移方程f[i][j]=Σf[i-1][k]*M[k][j](k∈S),边界f[0][i]=[i=0](i∈S)。
上述转移方程等价于行向量f[i]=f[i-1]*M,故f[n]=f[0]*Mn,又f[0]=[1,0,...,0],故f[n]=Mn。答案即为∑f[n][i](i∈S)。复杂度O(m2log2n)。
【参考代码】
1 #pragma GCC optimize(2) 2 #include <cstdio> 3 #include <cstring> 4 #define REP(i,low,high) for(register int i=(low);i<=(high);++i) 5 using namespace std; 6 7 static int n,m,AwD; char jiry[25]; int fail[25]={0}; 8 9 struct matrix 10 { 11 int mat[25][25]; matrix() {memset(mat,0,sizeof mat);} 12 matrix(const int&thr) 13 { 14 memset(mat,0,sizeof mat); REP(i,0,m-1) mat[i][i]=thr; 15 } 16 int&operator()(const int&x,const int&y) {return mat[x][y];} 17 matrix&operator=(const matrix&thr) 18 { 19 return memcpy(mat,thr.mat,sizeof thr.mat),*this; 20 } 21 matrix&operator=(const int&thr) 22 { 23 memset(mat,0,sizeof mat); REP(i,0,m-1) mat[i][i]=thr; return *this; 24 } 25 matrix operator*(const matrix&thr) 26 { 27 matrix ret; REP(i,0,m-1) REP(j,0,m-1) REP(k,0,m-1) 28 { 29 if((ret.mat[i][j]+=mat[i][k]*thr.mat[k][j]%AwD)>=AwD) 30 { 31 ret.mat[i][j]-=AwD; 32 } 33 } 34 return ret; 35 } 36 matrix&operator*=(const matrix&thr) 37 { 38 matrix ret; REP(i,0,m-1) REP(j,0,m-1) REP(k,0,m-1) 39 { 40 if((ret.mat[i][j]+=mat[i][k]*thr.mat[k][j]%AwD)>=AwD) 41 { 42 ret.mat[i][j]-=AwD; 43 } 44 } 45 return memcpy(mat,ret.mat,sizeof ret.mat),*this; 46 } 47 matrix operator^(const int&thr) 48 { 49 matrix bas(*this),ret(1); 50 for(register int i=thr;i;i>>=1,bas*=bas) if(i&1) ret*=bas; 51 return ret; 52 } 53 matrix&operator^=(const int&thr) 54 { 55 matrix bas(*this),ret(1); 56 for(register int i=thr;i;i>>=1,bas*=bas) if(i&1) ret*=bas; 57 return memcpy(mat,ret.mat,sizeof ret.mat),*this; 58 } 59 }M; 60 61 int main() 62 { 63 scanf("%d%d%d%s",&n,&m,&AwD,jiry+1),fail[1]=0; 64 REP(i,2,m) 65 { 66 int idx=fail[i-1]; for(;idx&&jiry[idx+1]!=jiry[i];idx=fail[idx]); 67 fail[i]=idx+(jiry[idx+1]==jiry[i]); 68 } 69 REP(i,0,m-1) REP(j,'0','9') 70 { 71 int idx=i; for(;idx&&jiry[idx+1]!=j;idx=fail[idx]); 72 idx+=jiry[idx+1]==j; if(idx<m&&++M(idx,i)==AwD) M(idx,i)=0; 73 } 74 M^=n; int ans=0; REP(i,0,m-1) if((ans+=M(i,0))>=AwD) ans-=AwD; 75 return printf("%d\n",ans),0; 76 }
We Secure, We Contain, We Protect.