[KMP+矩阵快速幂加速]BZOJ 1009——[HNOI2008]GT考试

来源:互联网 发布:dota后期三大核 知乎 编辑:程序博客网 时间:2024/06/08 21:20

题目梗概

给出一个不吉利数字A1A2...Am(0<=Ai<=9)M

求有多少个n位数满足不包含不吉利数字。

解题思路

读完题目便能想到一个显然的数位DP,F[i][j]表示长度为i,有长度为j的后缀与不吉利数字匹配。

考虑如何转移。

发现所有失配到j的状态都可以转移,所以要提前用KMP构造,假设我们构造出矩阵T。

但是发现还是超时。

接下来我们考虑这么修正答案:
[f[i][0],f[i][1],f[i][2]...f[i][m1]]=[f[i1][0],f[i1][1],f[i1][2]...f[i1][m1]]T

这个显然可以用矩阵快速幂优化。

#include<cstdio>#include<cstring>using namespace std;const int maxn=25;int n,m,tt,nxt[maxn],sum;char s[maxn];struct jz{    int n,m,x[maxn][maxn];}T,ans;void make_nxt(){    for (int i=2,j=0;i<=m;i++){        while (j&&s[j+1]!=s[i]) j=nxt[j];        if (s[j+1]==s[i]) j++;        nxt[i]=j;    }}jz mul(jz a,jz b){    jz c;memset(c.x,0,sizeof(c.x));    c.n=a.n;c.m=b.m;    for (int i=0;i<c.n;i++)    for (int j=0;j<c.m;j++)    for (int k=0;k<a.m;k++)    c.x[i][j]=(c.x[i][j]+a.x[i][k]*b.x[k][j])%tt;    return c;}jz qsm(jz x,int b){    jz c;memset(c.x,0,sizeof(c.x));    c.n=x.n;c.m=x.m;    for (int i=0;i<=c.n;i++) c.x[i][i]=1;    while(b>0){        if (b%2==1) c=mul(c,x);        x=mul(x,x);        b>>=1;    }    return c;}int main(){    freopen("exam.in","r",stdin);    freopen("exam.out","w",stdout);    scanf("%d%d%d",&n,&m,&tt);    scanf("%s",s+1);    make_nxt();    T.n=T.m=m;    for (int i=0;i<m;i++)    for (char j='0';j<='9';j++){        int k=i;        while(k&&s[k+1]!=j) k=nxt[k];        if (s[k+1]==j) k++;        if (k<m) T.x[i][k]=(T.x[i][k]+1)%tt;    }    ans.n=1,ans.m=m;ans.x[0][0]=1;ans=mul(ans,qsm(T,n));    for (int i=0;i<m;i++) sum=(sum+ans.x[0][i])%tt;    printf("%d\n",sum);    return  0;}
阅读全文
0 0