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

题意

给两个字符串,长度分别为 \(n\)\(m\),在给一个整数 \(k\),当 \(k=0\) 时要输出两串的公共子序列数量,当 \(k=1\) 时先输出每个公共子序列,然后输出数量。

思路

\(k=1\) 时是简单的,直接暴搜,在子序列自动机上跑。
\(k=0\) 时考虑 \(DP\),设 \(f_{i,j}\) 表示在 \(X\) 的子序列自动机上走到 \(i\)\(Y\) 的子序列自动机上走到 \(j\) 的方案数。转移时枚举下一个字符。
要开高精度,压位一下跑得飞快。

代码

// Problem: P4608 [FJOI2016] 所有公共子序列问题
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4608
// Memory Limit: 250 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T&x){
        x=0;char c=getchar();bool f=0;
        while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
        while(isdigit(c)) x=x*10+c-'0',c=getchar();
        f?x=-x:0;
    }
    template<typename T>
    inline void write(T x){
        if(x==0){putchar('0');return ;}
        x<0?x=-x,putchar('-'):0;short st[50],top=0;
        while(x) st[++top]=x%10,x/=10;
        while(top) putchar(st[top--]+'0');
    }
    inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
    inline void write(char c){putchar(c);}
    inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
    inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
    template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
    template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
    template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
const int maxn=3020;
string s,t;
int n,m,k;
int change(char c){
    if(c<='Z') return c-'A';
    return c-'a'+26;
}
class AM{
private:
    int nxt[maxn][60];
public:
    void build(string s){
        s=" "+s;
        for(int i=0;i<52;i++) nxt[s.size()][i]=s.size();
        for(int i=s.size()-1;i>=1;i--){
            for(int j=0;j<52;j++) nxt[i][j]=nxt[i+1][j];
            nxt[i][change(s[i])]=i;
        }
        for(int i=0;i<52;i++) nxt[0][i]=nxt[1][i];
    }
    int find_next(int w,int c){return nxt[w+1][c];}
}a,b;
namespace Part1{
    int cnt=0;
    void dfs(int u,int v,string s){
        if(u>n||v>m) return ;
        write(s),write("\n"),cnt++;
        for(char i='A';i<='Z';i++) dfs(a.find_next(u,change(i)),b.find_next(v,change(i)),s+i);
        for(char i='a';i<='z';i++) dfs(a.find_next(u,change(i)),b.find_next(v,change(i)),s+i);
    }
    void solve(){
        dfs(0,0,"");
        write(cnt);
    }
};
namespace Part2{
    struct Int{
        vector<int>a;
        friend void write(Int x){
            if(x.a.size()==0){write(0);return ;}
            write(x.a.back());
            for(int i=x.a.size()-2;i>=0;i--) printf("%08d",x.a[i]);
        }
        friend void read(Int&x){
            x.a.clear();
            string s;read(s);
            int be=0;
            while(be<s.size()&&s[be]=='0') be++;
            if(be==s.size()){x.a.push_back(0);return;}
            s=s.substr(be);
            int len=s.size();
            for(int i=len;i>0;i-=8){
                int ls=0;
                for(int j=max(0,i-8);j<i;j++) ls=ls*10+(s[j]-'0');
                x.a.push_back(ls);
            }
        }
        Int(int x){while(x) a.push_back(x%100000000),x/=100000000;}
        Int(){a.clear();}
        void clear(){a.clear();}
        Int operator+(const Int&x)const{
            vector<int>b=x.a,a=this->a;
            int n=max(b.size(),a.size());
            b.resize(n+1),a.resize(n+1);
            for(int i=0;i<n;i++) a[i]+=b[i];
            for(int i=0;i<n;i++) a[i+1]+=a[i]/100000000,a[i]%=100000000;
            while(!a.empty()&&!a.back()) a.pop_back();
            Int A;
            A.a.swap(a);
            return{A};
        }
    }f[maxn][maxn];
    void dfs(int u,int v){
        if(u>n||v>m) return ;
        if(f[u][v].a.size()) return ;
        f[u][v]=1;
        for(int i=0;i<52;i++){
            int ntu=a.find_next(u,i),ntv=b.find_next(v,i);
            dfs(ntu,ntv);
            f[u][v]=f[u][v]+f[ntu][ntv];
        }
    }
    void solve(){
        dfs(0,0);
        write(f[0][0]);
    }
};
signed main(){
    read(n,m,s,t,k);
    a.build(s),b.build(t);
    if(k==1){Part1::solve();return 0;}
    Part2::solve();
    return 0;
}
posted @ 2026-05-11 16:00  Link-Cut_Trees  阅读(11)  评论(0)    收藏  举报