[HNOI2008] GT考试
又是一道用KMP的字符串DP。
设f[i][j]为主串匹配到第i位,模式串最多匹配到第j位的方案数。
令g[i][j]表示模式串的前缀i可以转移到前缀j的方法数。
则:f[i][j]=(f[i-1][0]+f[i-1][1]+...+f[i-1][m-1])*g[k][j]。
用矩阵乘法优化一下递推即可。
1 #include<cstdio> 2 3 int n,m,mod; 4 char s[25]; 5 int nx[25]; 6 7 void getnx() 8 { 9 for(int i=2,j=1;i<=m+1;) 10 { 11 nx[i]=j; 12 while(j&&s[i]!=s[j])j=nx[j]; 13 i++,j++; 14 } 15 } 16 17 struct matrix 18 { 19 int a[25][25]; 20 }f,g; 21 22 matrix multi(matrix q,matrix w) 23 { 24 matrix e; 25 for(int i=0;i<m;i++) 26 { 27 for(int j=0;j<m;j++) 28 { 29 e.a[i][j]=0; 30 for(int k=0;k<m;k++) 31 { 32 e.a[i][j]=(e.a[i][j]+q.a[i][k]*w.a[k][j]%mod)%mod; 33 } 34 } 35 } 36 return e; 37 } 38 39 matrix ksm(matrix q,int t) 40 { 41 matrix ret=q; 42 t--; 43 while(t) 44 { 45 if(t&1)ret=multi(ret,q); 46 q=multi(q,q); 47 t>>=1; 48 } 49 return ret; 50 } 51 52 int main() 53 { 54 scanf("%d%d%d",&n,&m,&mod); 55 scanf("%s",s+1); 56 getnx(); 57 for(int i=0;i<m;i++) 58 { 59 for(int j=0;j<10;j++) 60 { 61 int p=i; 62 while(p&&s[p+1]!=j+'0')p=nx[p+1]-1; 63 if(s[p+1]==j+'0')p++; 64 if(p!=m)g.a[p][i]=(g.a[p][i]+1)%mod; 65 } 66 } 67 f=ksm(g,n); 68 long long ans=0; 69 for(int i=0;i<m;i++)ans=(ans+f.a[i][0])%mod; 70 printf("%lld",ans); 71 return 0; 72 }
写的时候,矩阵乘法忘打return了,调了半天都输出0......
后来Dr_J帮我找出了这个沙雕错误......