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;
}

浙公网安备 33010602011771号