P1439 【模板】最长公共子序列

1 篇文章 0 订阅
1 篇文章 0 订阅

题目

通过读题可以发现,这道题对于 50 % 50\% 50% 的数据可以用普通的 LCS 来解决,而对于 100 % 100\% 100% 的数据,我们就得考虑改变题目了。

我们可以当最长公共子序列都来自排列 P 1 P_1 P1,那么我们把 P 1 P_1 P1 重新标号,比如样例:

3 2 1 4 5

我们把 3 3 3 标号成 1 1 1 2 2 2 标号成 1 1 1 ……

我们可以标号成:

1 2 3 4 5

我们在把 P 2 P_2 P2 重新标号变为:

3 2 1 4 5

可以发现, P 1 , P 2 P_1,P_2 P1,P2 重新标号后,性质是一样的,也就是我们要求出重新标号的 P 2 P_2 P2 的 LIS 就行了。

方法一(普通求 LIS 加位运算优化):

不加位运算优化可得 50 50 50 分,加了可得 60 60 60 分。

#include<bits/stdc++.h>
#define all(x) x.begin(),x.end()
#define ll long long
#define ull unsigned long long
#define db double
#define x first
#define y second
#define fast ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define endl '\n'
#define pb push_back
#define swap(a,b) a=a^b,b=a^b,a=a^b
#define mem(x,a) memset(x,a,sizeof(x))
#define rep(l,r,i) for(int i=l,END##i=r;i<=END##i;i++)
#define per(r,l,i) for(int i=r,END##i=l;i>=END##i;i--)
#define sc scanf
#define pr printf
#define pii pair<int,int>
#define pll pair<ll,ll>
#define vi vector<int>
using namespace std;
const int MAXN=1e5+10;
int n,a[MAXN],b[MAXN],dp[MAXN],p[MAXN],t[MAXN];
int main(){
    fast
    cin>>n;
    rep(1,n,i)cin>>a[i];
    rep(1,n,i)cin>>b[i];
    rep(1,n,i)t[a[i]]=i;
    rep(1,n,i)p[i]=t[b[i]];
    int ans=0;
    rep(1,n,i){
        int t=0;
        rep(1,i-1,j)
            p[i]>p[j]?(t=t>dp[j]?t:dp[j]):0;
        dp[i]=t+1;
        ans=max(ans,dp[i]);
    }
    cout<<ans<<"\n";
    return 0;
}

方法二(二分优化 LIS):

#include<bits/stdc++.h>
#define all(x) x.begin(),x.end()
#define ll long long
#define ull unsigned long long
#define db double
#define x first
#define y second
#define fast ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define endl '\n'
#define pb push_back
#define swap(a,b) a=a^b,b=a^b,a=a^b
#define mem(x,a) memset(x,a,sizeof(x))
#define rep(l,r,i) for(int i=l,END##i=r;i<=END##i;i++)
#define per(r,l,i) for(int i=r,END##i=l;i>=END##i;i--)
#define sc scanf
#define pr printf
#define pii pair<int,int>
#define pll pair<ll,ll>
#define vi vector<int>
using namespace std;
const int MAXN=1e5+10,INF=0x3f3f3f3f;
int n,a[MAXN],b[MAXN],q[MAXN],p[MAXN],t[MAXN],len;
int main(){
    cin>>n;
    rep(1,n,i)cin>>a[i];
    rep(1,n,i)cin>>b[i];
    rep(1,n,i)t[a[i]]=i;
    rep(1,n,i)p[i]=t[b[i]];
    q[len]=-INF;
    rep(1,n,i){
        if(p[i]>q[len])q[++len]=p[i];
        else{
            int l=1,r=len;
            while(l<r){
                int mid=l+r>>1;
                if(q[mid]>p[i])r=mid;
                else l=mid+1;
            }
            q[l]=p[i];
        }
    }
    cout<<len<<"\n";
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值