【DP+树状数组】BZOJ1264-[AHOI2006]基因匹配Match

【题目大意】

给定n个数和两个长度为n*5的序列,两个序列中的数均有1..n组成,且1..n中每个数恰好出现5次,求两个序列的LCS。

【思路】

预处理每个数字在a[i]中出现的五个位置。f[i]示以a[i]为末尾的最长公共子串(*这样就可以避免讨论交叉)。

依次处理b[i],对于每个b[i]找到a[i]中的五个位置转移,用nowp表示,转移很简单:f[nowp]=max(f[nowp],query(nowp-1)+1),这里需要维护前缀最大值。

才知道前缀最大值可以用BIT来维护。

不过要注意的是,一定要从5 downto 1。为什么呢?由于nowp是升序排列的,如果从最小的开始,那么后来的f转移时可能会把先前求出来的f算进去,然而事实上它们对应着的是同一个b[i]。

所以要从大到小。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 const int MAXN=20000+50;
 8 int n;
 9 int a[5*MAXN],b[5*MAXN],e[5*MAXN],f[5*MAXN];
10 //f[i]表示以a[i]为末尾的最长公共子串,这样就可以避免讨论交叉 
11 int pos[MAXN][6];
12 int ans=0;
13 
14 int lowbit(int x) 
15 {
16     return (x&(-x));
17 }
18 
19 int query(int x)
20 {
21     int ret=0;//这里初值必须设为0而不是-1 
22     while (x>0) ret=max(ret,e[x]),x-=lowbit(x);
23     return ret;
24 }
25 
26 void update(int x,int delta)
27 {
28     while (x<=5*n) e[x]=max(e[x],delta),x+=lowbit(x);
29 } 
30 
31 void init()
32 {
33     memset(e,0,sizeof(e));
34     memset(f,0,sizeof(f));
35     memset(a,0,sizeof(a));
36     scanf("%d",&n);
37     for (int i=1;i<=5*n;i++) 
38     {
39         scanf("%d",&a[i]);
40         pos[a[i]][++pos[a[i]][0]]=i;
41     }
42     for (int i=1;i<=5*n;i++) scanf("%d",&b[i]); 
43 }
44 
45 void dp()
46 {
47     for (int i=1;i<=5*n;i++)
48         for (int j=5;j>=1;j--)//这里一定要从后往前 
49         {
50             int nowp=pos[b[i]][j];
51             f[nowp]=max(f[nowp],query(nowp-1)+1);
52             update(nowp,f[nowp]);
53             ans=max(ans,f[nowp]);
54         }
55     printf("%d\n",ans);
56 }
57 
58 int main()
59 {
60     init();
61     dp();
62     return 0;    
63 } 

 

posted @ 2016-08-09 11:48  iiyiyi  阅读(239)  评论(0编辑  收藏  举报