• 【BZOJ1009】GT考试(HNOI2008)-DP矩阵优化+KMP


    测试地址:GT考试
    做法:本题需要用到DP矩阵优化+KMP。
    f(i,j)为到X串第i位为止,没有一次完整出现整个A串,而末尾匹配到A串第j位的X串的数目。那么怎么考虑状态转移呢?注意到,第i+1位可能为0~9任何一个数字,那么当j或这个数字不同时,到第i+1位时匹配到的点也是不同的。也就是说,从f(i,j)可以转移到若干个f(i+1,x),那么我们要怎么求这个x呢?对于每个可能插入在末尾的数字,寻找以下字符串的最长后缀:A串的前j位+新加入的数字组成的字符串,使得这个后缀同时是A串的前缀,那么这个后缀的长度就是新的匹配点的位置,那么执行f(i+1,x)+=f(i,j)。特别地,j=m的转移不予考虑(因为已经出现了一次A串)。注意到这个过程和KMP算法非常相似,甚至完全一样,所以我们可以用KMP来优化这个过程。
    注意到上述的方法是O(nm)的,不可接受。注意到,因为A串是固定的,所以每次转移其实都是在一个确定好的状态转移图上进行,那么我们可以把这个图转化成矩阵的形式,其中矩阵的第i行第j列表示能从f(x,j1)转移到f(x+1,i1)的数字个数,然后我们把所有f(i,j)排成一些列向量,设Fi=(f(i,0) f(i,1) ... f(i,m))T,显然Fi=AFi1,于是Fn=AnF0,于是我们用矩阵快速幂算出An,然后右乘F0=(1 0 0 ... 0)T,即可求出Fn,显然我们要求的答案=m1i=0f(n,i),于是把Fn的前m个数加起来即可。上述所有运算都是在模K意义下进行,总的时间复杂度为O(m3logn)
    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int n,m,K,fail[30];
    char s[30];
    struct matrix {int s[25][25];} E,N,M[35];
    
    void init()
    {
        scanf("%d%d%d",&n,&m,&K);
        s[0]='#';
        scanf("%s",s+1);
    }
    
    void kmp()
    {
        fail[0]=-1;
        for(int i=1;i<=m;i++)
        {
            int x=fail[i-1];
            while(x!=-1&&s[x+1]!=s[i]) x=fail[x];
            if (s[x+1]!=s[i]) fail[i]=0;
            else fail[i]=x+1;
        }
    }
    
    matrix mult(matrix A,matrix B)
    {
        matrix S=N;
        for(int i=0;i<=m;i++)
            for(int j=0;j<=m;j++)
                for(int k=0;k<=m;k++)
                    S.s[i][j]=(S.s[i][j]+A.s[i][k]*B.s[k][j])%K;
        return S;
    }
    
    matrix power(int x)
    {
        matrix S=E;
        int i=0;
        while(x)
        {
            if (x&1) S=mult(S,M[i]);
            x>>=1,i++;
        }
        return S;
    }
    
    void build()
    {
        for(int i=0;i<=m;i++)
            for(int j=0;j<=m;j++)
                N.s[i][j]=0;
        M[0]=E=N;
        for(int i=0;i<=m;i++) E.s[i][i]=1;
        for(int i=0;i<m;i++)
            for(int j=0;j<=9;j++)
            {
                char c=j+'0';
                int x=i;
                while(x!=-1&&s[x+1]!=c) x=fail[x];
                if (s[x+1]!=c) M[0].s[0][i]=(M[0].s[0][i]+1)%K;
                else M[0].s[x+1][i]=(M[0].s[x+1][i]+1)%K;
            }
        for(int i=1;i<=32;i++) M[i]=mult(M[i-1],M[i-1]);
    }
    
    void solve()
    {
        matrix S=power(n);
        int ans=0;
        for(int i=0;i<m;i++) ans=(ans+S.s[i][0])%K;
        printf("%d",ans);
    }
    
    int main()
    {
        init();
        kmp();
        build();
        solve();
    
        return 0;
    }
  • 相关阅读:
    Pet Shop 4.0 详细解析(转) 沧海一粟
    如何制作Bat批处理文件 沧海一粟
    iOS开发Icon图标设置 (转) 沧海一粟
    Android金背大刀之ToggleButton之稍息立正
    Android碧水剑之DatePickerDialog、TimePickerDialog之岁月如梭
    平衡边界作业算法并发仿真测试基于三层架构的Web系统的基准性能
    Android鸳鸯刀之DatePicker、TimePicker之明年今日
    Android应用性能优化整体策略
    Android应用开发之性能测试之TraceView
    平衡边界作业算法并发仿真测试网络存储系统的响应时间
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793544.html
Copyright © 2020-2023  润新知