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;
}

 

posted @ 2018-04-25 09:34  Star_Feel  阅读(232)  评论(0编辑  收藏  举报