【KMP+DP+矩阵优化】BZOJ1009 [HNOI2008]GT考试

xiaoxiao2021-02-28  88

题面在这里

显然需要递推,定义 fi,j 为处理到第i位,不吉利数字匹配到第j位的方

显然答案就是

i=0m1fn,i 怎么转移状态?

对于 fi,j ,枚举i+1位的数字,用KMP得到不吉利数字新的匹配位置k,就有

fi+1,k+=fi,j 然而n是 109 级别的,显然不能这样搞

发现这个递推式是线性的,那么用矩阵优化就好了

我们必然能找到一个矩阵A,使得:

A×fi,0fi,1fi,2...fi,m=fi+1.0fi+1,1fi+1,2...fi+1,M 如何构造矩阵A?

考虑矩阵 Ax,y 表示 fi,y fi+1,x 的贡献

那么就枚举y和i+1这位的数字,用KMP得到x,然后累加

答案矩阵就是

An×100...0 示例程序:

#include<cstdio> #include<cstring> #define cl(x,y) memset(x,y,sizeof(x)) const int maxm=25; int n,m,p,fal[maxm]; char s[maxm]; struct matrix{ int n,m,s[maxm][maxm]; matrix operator*(const matrix &b){ matrix c;cl(c.s,0); c.n=n;c.m=b.m; for (int i=0;i<=c.n;i++) for (int j=0;j<=c.m;j++){ c.s[i][j]=0; for (int k=0;k<=m;k++) c.s[i][j]+=s[i][k]*b.s[k][j]; c.s[i][j]%=p; } return c; } }A,ans; matrix power(matrix a,int b){ matrix w=a,ans;ans.n=a.n;ans.m=a.m; cl(ans.s,0);for (int i=0;i<=m;i++) ans.s[i][i]=1; while (b){ if (b&1) ans=ans*w; w=w*w; b>>=1; } return ans; } int main(){ scanf("%d%d%d%s",&n,&m,&p,s+1); fal[1]=0; for (int i=2,j=0;i<=m;i++){ while (j&&s[j+1]!=s[i]) j=fal[j]; if (s[j+1]==s[i]) j++; fal[i]=j; } A.n=A.m=m; for (int y=0;y<m;y++) for (char i='0';i<='9';i++){ int j=y; while (j&&s[j+1]!=i) j=fal[j]; if (s[j+1]==i) j++; if (j<m) A.s[j][y]++; } ans.n=m;ans.m=0;ans.s[0][0]=1; ans=power(A,n)*ans; int res=0; for (int i=0;i<m;i++) res=(res+ans.s[i][0])%p; printf("%d",res); return 0; }
转载请注明原文地址: https://www.6miu.com/read-83965.html

最新回复(0)