luogu4608 [FJOI2016]所有公共子序列问题

Posted liguanlin1124

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu4608 [FJOI2016]所有公共子序列问题相关的知识,希望对你有一定的参考价值。

题目描述:

luogu

loj

题解:

序列自动机(?)+高精+普及dp。

这个是猫老师的序列自动机(字符串从1开始):

技术图片
void sol(char *s,int n,int t[N][53])

    memset(t[n],-1,sizeof(t[n]));
    for(int i=n-1;i>=0;i--)
    
        memcpy(t[i],t[i+1],sizeof(t[i]));
        t[i][ci(s[i+1])] = i+1;
    
序列自动机

$t$数组记录在位置$i$的后面加字符$j$能到达的最左边的位置。

对于这道题,直接对两个串构造序列自动机,然后爆搜即可。

$k=1$没啥好说的,$k=0$高精压18位。

时间复杂度$O(n^2)$。

代码:

技术图片
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 3020;
const ll M = 1000000000000000000ll;
struct bignum

    ll a[10];//8
    int len;
    void operator += (const bignum&x)
    
        int mx = max(len,x.len);
        for(int i=0;i<mx;i++)
        
            a[i]+=x.a[i];
            if(a[i]>=M)a[i+1]+=a[i]/M,a[i]%=M;
        
        while(a[len])len++;
    
    void operator += (const ll&x)
    
        a[0]+=x;
        for(int i=0;a[i]>=M;i++)a[i+1]+=a[i]/M,a[i]%=M;
        while(a[len])len++;
    
    void write()
    
        if(!len)puts("0");return ;
        printf("%lld",a[len-1]);
        for(int i=len-2;i>=0;i--)
            printf("%018lld",a[i]);
        puts("");
    
dp[2500050];
int n,m,k,t1[N][53],t2[N][53],id[N][N],tot=0,ans=0;
char s1[N],s2[N];
int ci(char ch)

    if(ch>=A&&ch<=Z)return ch-A;
    return ch-a+26;

char ic(int i)

    if(i<26)return A+i;
    return a+i-26;

void sol(char *s,int n,int t[N][53])

    memset(t[n],-1,sizeof(t[n]));
    for(int i=n-1;i>=0;i--)
    
        memcpy(t[i],t[i+1],sizeof(t[i]));
        t[i][ci(s[i+1])] = i+1;
    

int tl;
char now[N];
void dfs1(int a,int b)

    for(int i=1;i<=tl;i++)
        putchar(now[i]);
    putchar(\n);
    ans++;
    for(int i=0;i<52;i++)if(~t1[a][i]&&~t2[b][i])
    
        now[++tl] = ic(i);
        dfs1(t1[a][i],t2[b][i]);
        tl--;
    

void dfs2(int a,int b)

    if(id[a][b])return ;
    id[a][b]=++tot;
    dp[tot]+=1;
    for(int i=0;i<52;i++)if(~t1[a][i]&&~t2[b][i])
    
        dfs2(t1[a][i],t2[b][i]);
        dp[id[a][b]]+=dp[id[t1[a][i]][t2[b][i]]];
    


int main()

//    freopen("tt.in","r",stdin);
    scanf("%d%d%s%s%d",&m,&n,s1+1,s2+1,&k);
    sol(s1,m,t1),sol(s2,n,t2);
    if(k==1)dfs1(0,0);printf("%d\n",ans);return 0;
    dfs2(0,0);dp[id[0][0]].write();
    return 0;
View Code

 

以上是关于luogu4608 [FJOI2016]所有公共子序列问题的主要内容,如果未能解决你的问题,请参考以下文章

[Luogu4609][FJOI2016]建筑师

Luogu4609 FJOI2016 建筑师 第一类Stirling数

[FJOI2016]建筑师

FJOI2017 Day2

luogu P4585 [FJOI2015]火星商店问题

BZOJ 1002 && Luogu 2144 [FJOI 2007] 轮状病毒