[HNOI2008] GT考试

又是一道用KMP的字符串DP。

洛谷 P3193 传送门

bzoj 1009 传送门

设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 }
GT考试

写的时候,矩阵乘法忘打return了,调了半天都输出0......

后来Dr_J帮我找出了这个沙雕错误......

原文地址:https://www.cnblogs.com/cervusy/p/9688201.html