千帆渡

题目描述

这里写图片描述

数据范围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]]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值