1. 程式人生 > >bzoj1009 / P3193 [HNOI2008]GT考試

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