bzoj1009 [HNOI2008]GT考试(KMP+DP+矩阵倍增)

来源:互联网 发布:网络诈骗公司的员工 编辑:程序博客网 时间:2024/06/06 18:22

f[i][j]表示前i位准考证号,匹配到了不吉利串第j位。我们考虑如何将f[i][j]转移到f[i+1][j].首先用kmp处理出fail数组,假设现在在做前i位匹配到了第j位,那么对于i+1位可能出现的每个字符我们都从j开始匹配,看能转移到哪里去。就是这样:

f[0][0]=1;for(int i=0;i<=n;i++){for(int j=0;j<m;j++){for(int ch='0';ch<='9';ch++){int k=j;while(k>0&&s[k+1]!=ch) k=fail[k];if(s[k+1]==ch) k++;if(k!=m) f[i+1][k]+=f[i][j];}}}

然而n=10e9,显然会T,况且也存不下。。所以我们考虑矩阵倍增,如果现在匹配到了第i位,我们可能转移到第k位,则矩阵[i][k]++;至于怎么转移,跟上面一样。

#include <cstdio>#include <cstring>#include <algorithm>#define N 25#define ll long longinline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();return x*f;}int n,m,mod,fail[N],ans=0;char s[N];inline void getfail(){int k=0;fail[1]=0;for(int i=2;i<=m;++i){while(k&&s[k+1]!=s[i]) k=fail[k];if(s[k+1]==s[i]) ++k;fail[i]=k;}}struct matrix{int mat[N][N];matrix(bool t){memset(mat,0,sizeof(mat));if(t) for(int i=0;i<m;++i) mat[i][i]=1;}matrix operator*(matrix x){matrix res(0);for(int i=0;i<m;++i)for(int j=0;j<m;++j)for(int k=0;k<m;++k)res.mat[i][j]=(res.mat[i][j]+(ll)mat[i][k]*x.mat[k][j])%mod;return res;}matrix operator^(int k){matrix res(1),b(0);memcpy(b.mat,mat,sizeof(mat));for(;k;k>>=1,b=b*b)if(k&1) res=res*b;return res;}}base(0),a(0);int main(){//freopen("a.in","r",stdin);n=read();m=read();mod=read();scanf("%s",s+1);getfail();for(int i=0;i<m;++i){for(int ch='0';ch<='9';++ch){int k=i;while(k&&s[k+1]!=ch) k=fail[k];if(s[k+1]==ch) ++k;if(k!=m) base.mat[i][k]++;}}a.mat[0][0]=1;a=a*(base^n);for(int i=0;i<m;++i) ans=(ans+a.mat[0][i])%mod;printf("%d\n",ans);return 0;}


原创粉丝点击