码迷,mamicode.com
首页 > 其他好文 > 详细

[AHOI2006]基因匹配

时间:2018-11-03 01:53:50      阅读:146      评论:0      收藏:0      [点我收藏+]

标签:https   class   树状   +=   oid   const   main   pac   amp   

链接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;
}

[AHOI2006]基因匹配

标签:https   class   树状   +=   oid   const   main   pac   amp   

原文地址:https://www.cnblogs.com/Tyher/p/9898976.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!