bzoj1009 / 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 }