bzoj1009 / P3193 [HNOI2008]GT考试

P3193 [HNOI2008]GT考试

 

设$f[i][j]$表示主串匹配到第$i$个位置,不吉利数字匹配到第$j$个位置

$g[i][j]$表示加上某数字使子串原来最多能匹配到第$i$个数字,现在只能匹配到第$j$个数字的方案

那么可以列出方程

$f[i][j]=\sum_{k=0}^{m-1}f[i-1][k]*g[k][j]$

而后面的方案数暴力枚举似乎不行

仔细观察发现介个可以用kmp搞鸭

但是$n<=1e9$,$O(n)$也不行

再仔细观察发现这个式子可以用矩乘搞鸭

蓝后就结束了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define re register
 5 using namespace std;
 6 char q[22];
 7 int n,m,k,f[22],ans;
 8 struct matrix{
 9     int a[22][22];
10     matrix(){memset(a,0,sizeof(a));}
11     matrix operator * (const matrix &tmp) const{
12         matrix c;
13         for(int i=0;i<m;++i)
14             for(int j=0;j<m;++j)
15                 for(int u=0;u<m;++u)
16                     c.a[i][j]=(c.a[i][j]+a[i][u]*tmp.a[u][j]%k)%k;
17         return c;
18     }
19     matrix Pow(matrix x,int y){
20         matrix res;
21         for(int i=0;i<m;++i) res.a[i][i]=1;
22         for(;y;y>>=1,x=x*x)
23             if(y&1) res=res*x;
24         return res;
25     }
26 }st,g;
27 void kmp(){//kmp处理方案数
28     int len=strlen(q);
29     for(int i=1,j;i<len;++i){
30         for(j=f[i];j&&q[i]!=q[j];j=f[j]);
31         f[i+1]= q[i]==q[j] ? j+1:0;
32     }
33     for(int i=0,j;i<len;++i)
34         for(char u='0';u<='9';++u){
35             for(j=i;j&&q[j]!=u;j=f[j]);
36             if(q[j]==u) ++j;
37             if(j<m) ++g.a[i][j];
38         }
39 }
40 int main(){
41     scanf("%d%d%d",&n,&m,&k);
42     scanf("%s",q); kmp();
43     st.a[0][0]=1; g=g.Pow(g,n);
44     st=st*g;
45     for(int i=0;i<m;++i) ans=(ans+g.a[0][i])%k;
46     printf("%d",ans);
47     return 0;
48 }
View Code

 

posted @ 2018-11-03 17:17  kafuuchino  阅读(196)  评论(0编辑  收藏  举报