BZOJ 1009 [HNOI2008]GT考试
设dp[i][j]为当前是第i位考号、现在匹配到A的第j位的方案数
因为假如当前匹配j位,如果选择的下一位与A[j+1]不同,新的匹配位数是num(fail[j])而不是0
设由匹配j位转移到匹配k位的方案数为c[j][k]那么
$dp[i][j] = \sum f[i-1][k]*c[k][j] $
这个式子是线性的,计算出t矩阵的n次幂,乘以初始矩阵
c矩阵枚举当前匹配多少位,利用KMP计算c矩阵
#include<cstdio> #include<cstring> #include<algorithm> const int maxn = 33; int n,m,k,T[maxn],next[maxn]; struct Matrix { int f[maxn][maxn]; Matrix () { memset(f,0,sizeof f);}; void clear() { memset(f,0,sizeof f);}; }a,F; Matrix operator * (const Matrix & a,const Matrix & b) { Matrix ret; for(int i=0;i<m;++i) for(int j=0;j<m;++j) for(int kk=0;kk<m;++kk) ret.f[i][j]=(ret.f[i][j]+a.f[i][kk]*b.f[kk][j])%k; return ret; } void get_next() { next[1]=0; for(int j=0,i=2;i<=m;++i) { for(;j && T[j+1] != T[i];j=next[j]); if(T[j+1]==T[i]) ++j; next[i]=j; } } void get_a() { for(int i=0;i<m;++i) for(int k,j=0;j<10;++j) { for(k=i; k && T[k+1]!=j; k=next[k]); if(T[k+1]==j) ++k; a.f[i][k]++; } } void pow() { Matrix tmp=a; a.clear(); for(int i=0;i<m;++i) a.f[i][i]=1; for(;n;n>>=1,tmp=tmp*tmp) if(n&1) a=a*tmp; } int main() { char c[maxn]; scanf("%d%d%d%s",&n,&m,&k,c+1); for(int i=1;i<=m;++i) T[i]=c[i]-'0'; get_next();get_a();pow(); int Ans=0; F.f[0][0]=1; F=F*a; for(int i=0;i<m;++i) Ans=(Ans+F.f[0][i])%k; printf("%d\n",Ans); }