xjb——洛谷 P1439 排列LCS问题

https://www.luogu.org/problem/show?pid=1439

这个一看就是n*n的暴力嘛,但是n有点大…
因为是两个排列,换句话说没有重复的数字;
那我们可以转化一下

比如样例

5
3 2 1 4 5
1 2 3 4 5

我们把下面一行的值变成上面一行的位置

3 2 1 4 5

那么直接最长上升子序列就好了
为什么呢?
比如第二行第一个数1
如果我们选了1,那么后面是不是只可以选择在第一行1后面的数了;
就是这个道理;

然后对于最长上升子序列我们有一个基于单调栈和二分的算法n*logn
就是维护一个递增的栈;
当前我们的值是x;
如果x>栈顶,那么直接加入;
不然我们就二分找到第一个大于x的数,直接替换;
因为x之后的数,全可以接在x的后面,所以直接替换就可以了;
最后答案就是栈的高度;
但是方案并不是栈的元素;
不好意思,这种方法不可以记录方案的;

#include<bits/stdc++.h>
#define Ll long long
using namespace std;
const int N=1e5+5;
int f[N],a[N],v[N],top;
int n,m,x,ans;
int er(int x){
    if(x>v[top])return ++top;
    int l=1,r=top,ans,mid;
    while(r>=l){
        mid=l+r>>1;
        if(v[mid]>x)ans=mid,r=mid-1;else l=mid+1;
    }
    return ans;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&x),f[x]=i;
    for(int i=1;i<=n;i++){
        scanf("%d",&x);
        v[er(f[x])]=f[x];
    }
    printf("%d",top);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值