题目大意
求两个序列的最长递增子序列
DP
设f[i,j]表示在a的前i里找一个与b的第j个作为最后一次匹配最大的序列长度。
则
f[i,j]=f[i−1,j]
f[i,j]=maxf[i−1,k]+1,b[k]<b[j],a[i]=b[j]
即f[i,j]=maxf[i−1,k]+1,b[k]<a[i]
于是可以简单维护f[i-1,k]的最大值
#include<cstdio>
#include<algorithm>
#include<map>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=5000+10;
map<ll,int> bz;
int a[maxn],b[maxn],d[maxn],sum[maxn],num[maxn][2],id[maxn],sta[maxn];
int f[maxn][maxn],g[maxn][maxn][2];
int i,j,k,l,r,t,n,m,top,tot,cnt;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
int main(){
//freopen("sail.in","r",stdin);//freopen("t2.out","w",stdout);
n=read();
fo(i,1,n){
a[i]=read();
bz[a[i]]=1;
}
m=read();
fo(i,1,m){
b[i]=read();
if (bz[b[i]]==1){
bz[b[i]]=2;
d[++top]=b[i];
}
}
t=0;
fo(i,1,n)
if (bz[a[i]]==2) a[++t]=a[i];
n=t;
t=0;
fo(i,1,m)
if (bz[b[i]]==2) b[++t]=b[i];
m=t;
sort(d+1,d+top+1);
fo(i,1,n) a[i]=lower_bound(d+1,d+top+1,a[i])-d;
fo(i,1,m) b[i]=lower_bound(d+1,d+top+1,b[i])-d;
if (!n){
printf("0\n");
return 0;
}
fo(i,1,n){
t=0;l=r=0;
fo(j,1,m){
if (a[i]==b[j]){
if (t+1>f[i][j]){
f[i][j]=t+1;
g[i][j][0]=l;
g[i][j][1]=r;
}
}
if (f[i-1][j]>f[i][j]){
f[i][j]=f[i-1][j];
g[i][j][0]=i-1;
g[i][j][1]=j;
}
if (b[j]<a[i])
if (f[i-1][j]>t){
t=f[i-1][j];
l=i-1;
r=j;
}
}
}
k=0;
fo(i,1,m)
if (f[n][i]>f[n][k]) k=i;
printf("%d\n",f[n][k]);
j=n;
cnt=0;
while (j){
l=g[j][k][0];
t=g[j][k][1];
if (f[l][t]<f[j][k]) sta[++cnt]=d[a[j]];
j=l;k=t;
}
while (cnt) printf("%d ",sta[cnt--]);
}