zoukankan      html  css  js  c++  java
  • 【LOJ2172】所有公共子序列问题(FJOI2016)-序列自动机+DP+高精度

    测试地址:所有公共子序列问题
    做法:本题需要用到序列自动机+DP+高精度。
    序列自动机,顾名思义,就是能识别一个字符串所有本质不同的子序列的自动机。构建的方法十分简单:只需要从字符串上的每个点,向后面每种字符第一次出现的位置连边即可。唯一要注意的是,就像是所有其他自动机一样,还是要多建立一个空点表示空串的。因此,令字符集大小为s,字符串长度为n,那么构建序列自动机的时间复杂度是O(sn)的。
    那么回到这题,我们很快想到建立两个序列自动机,然后求公共子序列数目,实际上就是两个自动机同时匹配,只走两边都可以走的边,问有多少种走法。令f(i,j)为第一个自动机匹配到i点,第二个自动机匹配到j点,后面能够匹配出的公共子序列数目,记忆化搜索转移即可。
    然而答案可能很大,需要高精度,又因为空间的限制,需要压位,这样我们就可以通过此题了。
    (非常奇怪,一开始在洛谷上交怎么都RE,结果同一份代码交到LOJ就A了…)
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int w=1000000000;
    int n,m,k,nxta[3020][60],nxtb[3020][60],nx[60];
    char a[3020],b[3020],path[3020];
    bool vis[3020][3020]={0};
    struct hd
    {
        int siz;
        int s[21];
        void output()
        {
            printf("%d",s[siz-1]);
            for(int i=siz-2;i>=0;i--)
                printf("%09d",s[i]);
        }
    }f[3020][3020];
    
    hd operator + (hd a,hd b)
    {
        hd s=a;
        for(int i=0;i<b.siz;i++)
            s.s[i]+=b.s[i];
        s.siz=max(a.siz,b.siz);
        for(int i=0;i<s.siz;i++)
            if (s.s[i]>=w)
            {
                s.s[i+1]+=s.s[i]/w;
                s.s[i]%=w;
                if (i==s.siz-1) s.siz++;
            }
        return s;
    }
    
    void build(char *s,int len,int (*nxt)[60])
    {
        memset(nx,0,sizeof(nx));
        for(int i=len;i>=1;i--)
        {
            for(int j=0;j<=59;j++)
                nxt[i][j]=nx[j];
            nx[s[i]-'A']=i;
        }
        for(int j=0;j<=59;j++)
            nxt[0][j]=nx[j];
    }
    
    void dfs(int len,int a,int b)
    {
        for(int i=1;i<=len;i++)
            printf("%c",path[i]);
        printf("
    ");
        for(int i=0;i<=59;i++)
            if (nxta[a][i]&&nxtb[b][i])
            {
                path[len+1]=i+'A';
                dfs(len+1,nxta[a][i],nxtb[b][i]);
            }
    }
    
    void dp(int a,int b)
    {
        if (vis[a][b]) return;
        vis[a][b]=1;
        memset(f[a][b].s,0,sizeof(f[a][b].s));
        f[a][b].siz=1;
        f[a][b].s[0]=1;
        for(int i=0;i<=59;i++)
            if (nxta[a][i]&&nxtb[b][i])
            {
                dp(nxta[a][i],nxtb[b][i]);
                f[a][b]=f[a][b]+f[nxta[a][i]][nxtb[b][i]];
            }
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        scanf("%s%s",a+1,b+1);
        scanf("%d",&k);
    
        build(a,n,nxta);
        build(b,m,nxtb);
    
        if (k) dfs(0,0,0);
        dp(0,0);
        f[0][0].output();
    
        return 0;
    }
  • 相关阅读:
    python之高阶函数
    [第二版]多线程的发送与接收
    基本函数与结构
    unp.h
    gdb调试命令
    System V共享内存区
    Posix 共享内存区
    System V信号量
    Posix 信号量
    记录锁
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793326.html
Copyright © 2011-2022 走看看