【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("\n");
    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;
}
posted @ 2018-06-17 17:33  Maxwei_wzj  阅读(113)  评论(0编辑  收藏  举报