【解题思路】

  先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 }
View Code