[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 }

 

posted @ 2017-09-26 21:04  halfrot  阅读(140)  评论(0编辑  收藏  举报