題目描述
數據範圍n,m<=5000,ai,bi <=230
dp
設f[i][j]表示a的前i位中的某一位和b的第j位是最後一對匹配時的最優答案,f[i][j]顯然可以由f[i-1][j]轉移過來。
如果a[i]=b[j],則f[i][j]=max(f[i][j],f[i-1][j1]+1)(b[j1]<=a[i],j1<=j)
由於枚舉j是遞增的,設d=max(f[i-1][j1])當a[i]>b[j]時就更新一下d,這樣f[i][j]=d+1,
轉移O(1),總複雜度O(n^2).
至於輸出方案,轉移的時候記錄一下就好了。
代碼
(不必打離散化,我打暴力的時候打了,就懶得刪了)
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define ll long long
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=5000+5;
int i,j,n,m,ans,num,l,p[maxn];
ll w[maxn];
struct ar{
int i1,i2;ll x;
} c[maxn*2];
int a[maxn],b[maxn];
struct aa{
bool friend operator <(aa x,aa y){
return x.k<y.k;
}
int k,x,y,p;
}f[maxn][maxn],d,d1;
bool cmp(ar x,ar y){
return x.x<y.x;
}
int main(){
scanf("%d",&n);fo(i,1,n) {scanf("%lld",&c[i].x);c[i].i1=i;}
scanf("%d",&m);fo(i,1,m) {scanf("%lld",&c[n+i].x);c[n+i].i2=i;}
sort(c+1,c+1+n+m,cmp);num=0;
fo(i,1,n+m) {
if (c[i].x!=c[i-1].x) w[++num]=c[i].x;
if (c[i].i1>0) a[c[i].i1]=num;else b[c[i].i2]=num;
}
fo(i,1,n) {
d.k=d.x=d.y=0;
fo(j,1,m) {
f[i][j]=f[i-1][j];
if (a[i]==b[j]) {
d.k++;
if (d.k>f[i][j].k) {
f[i][j]=d;
f[i][j].p=a[i];
}d.k--;
}
if (a[i]>b[j]) {
if (f[i-1][j].k>d.k) {
d.k=f[i-1][j].k;
d.x=i-1;
d.y=j;
}
}
d1=max(d1,f[i][j]);
}
}
d=d1;ans=d.k;
fod(i,ans,1) {
p[i]=d.p;
d=f[d.x][d.y];
}
printf("%d\n",ans);
fo(i,1,ans) printf("%lld ",w[p[i]]);
}