bzoj1264[AHOI2006]基因匹配Match

bzoj1264[AHOI2006]基因匹配Match

题意:

某种序列由n种数组成,每种数在该序列中正好出现5次。对于两个这样的序列s1和s2,如果存在一个序列u同时成为s1和s2的子序列,则称u是s1和s2的公共子序列。子序列的概念:若从一个序列s中任意抽取一些数字,将它们仍按在s中的顺序排列成一个新串u,则称u是s的一个子序列。已知两个等长DNA序列s1和s2,求s1和s2最长公共子序列的长度。

题解:

dp+树状数组,题解太难写,摘抄一下

LCS的决策+1的条件是a[i]==b[j] 于是我们记录a序列中每个数的5个位置

扫一下b[i] 对于每个b[i]找到b[i]在a中的5个位置 这5个位置的每个f[pos]值都可以被b[i]更新 于是找到f[1]到f[pos-1]的最大值+1 更新f[pos]即可

这个用树状数组维护 时间复杂度O(nlogn)

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 #define dec(i,j,k) for(int i=j;i>=k;i--)
 7 #define lb(x) x&-x
 8 using namespace std;
 9 
10 int c[200000],n,a[40000][6],an[40000],f[200000],ans;
11 inline int query(int x){int q=0; while(x)q=max(q,c[x]),x-=lb(x); return q;}
12 inline void update(int x,int y){while(x<=n*5)c[x]=max(c[x],y),x+=lb(x);}
13 int main(){
14     scanf("%d",&n); memset(an,0,sizeof(an)); memset(c,0,sizeof(c));
15     inc(i,1,n*5){int x; scanf("%d",&x); a[x][++an[x]]=i;} ans=0;
16     memset(f,0,sizeof(f));
17     inc(i,1,n*5){
18         int x; scanf("%d",&x);
19         dec(j,5,1){
20             int y=a[x][j]; f[y]=max(f[y],query(y-1)+1);
21             update(y,f[y]); ans=max(ans,f[y]);
22         }
23     }
24     printf("%d",ans);
25     return 0;
26 }

20160423

原文地址:https://www.cnblogs.com/YuanZiming/p/5703348.html