BZOJ1009: [HNOI2008]GT考试
【传送门:BZOJ1009】
简要题意:
给出n,m,k,给出长度为m的不吉利串,求出长度为n的数字序列中不存在一个子串为不吉利串的序列数,答案%k
题解:
神矩乘+KMP
f[i][j]表示当前枚举到第i位,和不吉利数字匹配到第j位
a[i][j]表示匹配到第i位,转移到第j位方案数(可以用KMP求出来)
f[i+1][k]=f[i][j]*a[j][k]的方程就显然可以搞出来
然后用矩乘加速,答案为f[n][0]+f[n][1]+...+f[n][m-1]
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int Mod; struct node { int a[21][21]; node() { memset(a,0,sizeof(a)); } }cmp,ans; int m; node chengfa(node a,node b) { node c; for(int i=0;i<m;i++) { for(int j=0;j<m;j++) { for(int k=0;k<m;k++) { c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%Mod; } } } return c; } node p_mod(node a,int b) { node ans; for(int i=0;i<m;i++) ans.a[i][i]=1; while(b!=0) { if(b%2==1) ans=chengfa(ans,a); a=chengfa(a,a);b/=2; } return ans; } char st[21]; int a[21],p[21]; int main() { int n; scanf("%d%d%d",&n,&m,&Mod); scanf("%s",st+1); p[1]=0;a[1]=st[1]-'0'; for(int i=2;i<=m;i++) { a[i]=st[i]-'0'; int j=p[i-1]; while(j!=0&&a[j+1]!=a[i]) j=p[j]; if(a[j+1]==a[i]) j++; p[i]=j; } for(int i=0;i<m;i++) { for(int j=0;j<=9;j++) { int k=i; while(k!=0&&a[k+1]!=j) k=p[k]; if(a[k+1]==j) k++; cmp.a[k][i]=(cmp.a[k][i]+1)%Mod; } } cmp=p_mod(cmp,n); int ans=0; for(int i=0;i<m;i++) ans=(ans+cmp.a[i][0])%Mod; printf("%d\n",ans); return 0; }
渺渺时空,茫茫人海,与君相遇,幸甚幸甚