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