[BZOJ1009][HNOI2008]GT考试 DP+矩阵快速幂+KMP
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1009
我们令$dp(i,j)$表示已经填了$i$位,而且后缀与不幸运数字匹配了$j$位,那么转移方程就是$dp(i,j)=dp(i,k)*a(j,k)$,其中$a(j,k)$表示从$j$位可以转移到$k$位的方案数,这个可以利用kmp的ne数组来计数求得。因为DP方程是线性的,所以可以用矩阵优化。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 char s[25]; 6 int ne[25]; 7 int N,M,K; 8 struct Matrix{ 9 int lx,ly,a[21][21]; 10 Matrix(int _lx=0,int _ly=0){ 11 memset(a,0,sizeof(a)); 12 lx=_lx; 13 ly=_ly; 14 } 15 Matrix operator * (const Matrix &_)const{ 16 Matrix t(ly,_.lx); 17 for(int i=0;i<ly;i++) 18 for(int j=0;j<_.lx;j++) 19 for(int k=0;k<lx;k++) 20 t.a[i][j]=(t.a[i][j]+a[i][k]*_.a[k][j]%K)%K; 21 return t; 22 } 23 }F; 24 Matrix ksm(Matrix x, int y){ 25 Matrix base=x,sum(M,M); 26 for(int i=0;i<M;i++) sum.a[i][i]=1; 27 while(y){ 28 if(y&1) sum=sum*base; 29 base=base*base; 30 y>>=1; 31 } 32 return sum; 33 } 34 int main(){ 35 scanf("%d%d%d%s",&N,&M,&K,s+1); 36 ne[0]=ne[1]=0; 37 for(int i=2,j=0;i<=M;i++){ 38 while(j&&s[i]!=s[j+1]) j=ne[j]; 39 if(s[j+1]==s[i]) j++; 40 ne[i]=j; 41 } 42 F.lx=M; 43 F.ly=M; 44 for(int i=0;i<M;i++){ 45 for(int j='0';j<='9';j++){ 46 int k=i; 47 while(k&&s[k+1]!=j) k=ne[k]; 48 if(s[k+1]==j) k++; 49 F.a[i][k]++; 50 } 51 } 52 Matrix A(M,M); 53 A.a[0][0]=1; 54 A=A*ksm(F,N); 55 int ans=0; 56 for(int i=0;i<M;i++) ans=(ans+A.a[0][i])%K; 57 printf("%d\n",ans); 58 return 0; 59 }