[AHOI2006]基因匹配
阿新 • • 發佈:2018-11-02
連結P4303 [AHOI2006]基因匹配
- 求兩個序列的最長公共子序列,滿足每個數出現不超過\(5\)次,\(n\leq 10^5\)。
- 一般的最長公共子序列是\(O(n^2)\)的,考慮這個題的不一樣性質在哪裡。
- 滿足每個數出現不超過\(5\)次,意味合法的轉移點不多。
- 那麼對於\(a\)序列中的每個數\(a_i\),他的合法轉移點不會超過\(5\)個。
- 所以把每個數的合法轉移點扣出來,這樣就得到了一個長度為\(5*n\)的序列。
- 如果選擇一個數,就相當於選擇了一個轉移點轉移,因為要求是原串的子序列,所以轉移點位置一定是單調上升的。
- 所以對於每個數的合法轉移點之間要倒序排列,這樣才能滿足一個數的轉移點只會選擇一個。
- 現在問題轉化成,給出一個長度為\(5*n\)的序列,求最長上升子序列。
- 這個就爛大街了,樹狀陣列或者二分棧隨便維護一下即可,複雜度\(O(5*nlogn)\)
#include<bits/stdc++.h> #define R register int #define low(x) (x&(-x)) using namespace std; const int N=20001; const int M=500001; int n,m,w[M],f[M],tot,ans,te[M]; vector<int>G[N]; void add(R x,R v){while(x<=m)te[x]=max(te[x],v),x+=low(x);} int query(R x){R v=0;while(x)v=max(te[x],v),x-=low(x);return v;} int gi(){ R x=0,k=1;char c=getchar(); while(c!='-'&&(c<'0'||c>'9'))c=getchar(); if(c=='-')k=-1,c=getchar(); while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar(); return x*k; } int main(){ n=gi(),m=n*5; for(R i=1,u;i<=m;++i) u=gi(),G[u].push_back(i); for(R i=1,u;i<=m;++i){ u=gi(); for(R j=4;j>=0;--j)w[++tot]=G[u][j]; } for(R i=1;i<=tot;++i) f[i]=query(w[i]-1)+1,add(w[i],f[i]),ans=max(ans,f[i]); cout<<ans<<endl; return 0; }