洛谷P1439 最长公共子序列

传送门:

https://www.luogu.com.cn/problem/P1439

最长公共子序列可以考虑转化为最大上升子序列。很容易想到用结构体存储元素i(1<=i<=n)分别在两个序列中出现的位置,按其在第一个序列中出现的位置排序,对样例便有:

x[i].a:1 2 3 4 5
x[i].b:3 2 1 4 5

此时i在a中出现顺序一定从前往后排列,求最大公共子序列长度只需找到b中最长的上升子序列长度即可。

看下数据,n最大可以达到1e5,显然普通dp的O(n2)求法会爆,便能想到二分。

 1 #include<bits/stdc++.h>
 2 #define ff(i,s,e) for(int i=s;i<=e;i++)
 3 using namespace std;
 4 inline int read(){
 5     register int x=0,f=1;register char ch=getchar();
 6     while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}
 7     while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
 8     return x*f;
 9 }
10 const int m=100005;
11 int n,f[m];
12 struct qwq{
13     int a,b;
14 }x[m];
15 bool cmp(qwq x,qwq y){
16     return x.a<y.a;
17 }
18 int find(int l,int r,int x){//二分在已知上升序列中找第一个大于x的数 
19     while(l<=r){
20         int mid=(l+r)/2;
21         if(f[mid]<x) l=mid+1;
22         else r=mid-1;
23     }
24     return l;
25 }
26 int main(){
27     n=read();
28     ff(i,1,n) x[read()].a=i;
29     ff(i,1,n) x[read()].b=i;
30     sort(x+1,x+n+1,cmp);
31     int len=0; 
32     ff(i,1,n){
33         if(x[i].b>f[len])//若大于当前最大上升子序列最大元素,存储 
34             f[++len]=x[i].b;
35         else{f[find(1,len,x[i].b)]=x[i].b;}//用x替换大于x的数,保证后面解最优 
36     }
37     printf("%d",len);
38     return 0;
39 }

 

posted @ 2022-02-10 13:55  专吃小仙女  阅读(42)  评论(0)    收藏  举报