1. 程式人生 > 其它 >洛谷P1439 最長公共子序列

洛谷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 }