[bzoj1264]基因匹配

首先朴素dp的方程,即$f[i][j]=max(f[i][j-1],f[i-1][j],(a[i]==b[j])*(f[i-1][j-1]+1))$,这中间特殊的转移只在a[i]=b[j]时,而在这道题中与a[i]相等的b[j]只有5个,考虑利用这一性质
先预处理每一种数的位置,在枚举i的同时,用线段树来维护f[i]这个数组,然后对于特殊的5个位置从上一轮转移,并对后面的区间max即可

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 100005
 4 #define L (k<<1)
 5 #define R (L+1)
 6 #define mid (l+r>>1)
 7 int n,x,a[N],b[N][11],f[N<<2];
 8 void down(int k){
 9     f[L]=max(f[L],f[k]);
10     f[R]=max(f[R],f[k]);
11     f[k]=0;
12 }
13 void update(int k,int l,int r,int x,int y,int z){
14     if ((l>y)||(x>r))return;
15     if ((x<=l)&&(r<=y)){
16         f[k]=max(f[k],z);
17         return;
18     }
19     down(k);
20     update(L,l,mid,x,y,z);
21     update(R,mid+1,r,x,y,z);
22 }
23 int query(int k,int l,int r,int x){
24     if (!x)return 0;
25     if (l==r)return f[k];
26     down(k);
27     if (x<=mid)return query(L,l,mid,x);
28     return query(R,mid+1,r,x);
29 }
30 int main(){
31     scanf("%d",&n);
32     n*=5;
33     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
34     for(int i=1;i<=n;i++){
35         scanf("%d",&x);
36         b[x][++b[x][0]]=i;
37     }
38     for(int i=1;i<=n/5;i++)b[i][6]=n+1;
39     for(int i=1;i<=n;i++)
40         for(int j=5;j;j--)
41             update(1,1,n,b[a[i]][j],b[a[i]][j+1]-1,query(1,1,n,b[a[i]][j]-1)+1);
42     printf("%d",query(1,1,n,n));
43 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/12493076.html