bzoj 1009 [HNOI2008]GT考试(DP+KMP+矩阵乘法)
【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=1009
【题意】
给定一个字符串T,问长度为n且不包含串T的字符串有多少种。
【思路】
设长度为i的串与T匹配长度为j,有转移式如下:
f[i+1][j+1]+=f[i][j]
f[i+1][k]+=f[i][j]
第一种是匹配成功,第二种是匹配失败。注意如果匹配失败匹配长度并不一定变为0,考虑如果匹配失败f[i][j]可以转移到哪,假设新字符为c,则可以用KMP算法预处理出fail数组,从而计算出应该转移到的位置pos。
考虑到n比较大,而f的计算又是有规律的,我们采用矩阵乘法优化DP。
如果i可以转移到pos,则在转移矩阵A中使A[i][pos]++,代表f[cur][pos]的计算需要累加一次f[cur-1][i]。
注意程序中的fail[i]代表的是i刚好与fail[i]匹配。
【代码】
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #define FOR(a,b,c) for(int a=b;a<=c;a++) 5 using namespace std; 6 7 typedef long long ll; 8 const int maxn = 25; 9 10 char s[maxn]; 11 int f[maxn],MOD,n,m,K; 12 13 struct Matrix { 14 int r,c; 15 ll N[maxn][maxn]; 16 void init(int r,int c) { 17 this->r=r,this->c=c; 18 memset(N,0,sizeof(N)); 19 } 20 Matrix operator * (const Matrix B) const { 21 Matrix C; C.init(r,B.c); 22 for(int i=0;i<r;i++) 23 for(int j=0;j<B.c;j++) 24 for(int k=0;k<c;k++) 25 C.N[i][j]=(C.N[i][j]+(ll)N[i][k]*B.N[k][j])%MOD; 26 return C; 27 } 28 Matrix Pow(int p) { 29 Matrix tmp=*this,ans; 30 ans.init(r,r); 31 for(int i=0;i<r;i++) ans.N[i][i]=1; 32 while(p) { 33 if(p&1) ans=ans*tmp; 34 tmp=tmp*tmp; p>>=1; 35 } 36 return ans; 37 } 38 }A; 39 40 void get_fail() //所构造fail 意为i与f[i]处匹配 41 { 42 int j=0; 43 for(int i=2;i<m;i++) { 44 while(j&&s[j+1]!=s[i]) j=f[j]; 45 if(s[j+1]==s[i]) j++; 46 f[i]=j; 47 } 48 } 49 50 int main() 51 { 52 scanf("%d%d%d%s",&n,&m,&MOD,s+1); 53 get_fail(); 54 A.init(m+1,m+1); 55 FOR(i,0,m-1) 56 FOR(j,0,9) { 57 int x=i; 58 while(x&&s[x+1]-'0'!=j) x=f[x]; 59 if(j==s[x+1]-'0') A.N[i][x+1]++; 60 else A.N[i][0]++; 61 } 62 A=A.Pow(n); 63 ll ans=0; 64 FOR(i,0,m-1) ans=(ans+A.N[0][i])%MOD; 65 printf("%lld\n",ans); 66 return 0; 67 }
posted on 2016-03-29 17:09 hahalidaxin 阅读(191) 评论(0) 编辑 收藏 举报