【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 } 
时间: 2024-10-06 18:13:08

【DP+树状数组】BZOJ1264-[AHOI2006]基因匹配Match的相关文章

BZOJ-1264 :[AHOI2006]基因匹配Match(树状数组+DP)

1264: [AHOI2006]基因匹配Match Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 904  Solved: 578[Submit][Status][Discuss] Description 基因匹配(match) 卡卡昨天晚上做梦梦见他和可可来到了另外一个星球,这个星球上生物的DNA序列由无数种碱基排列而成(地球上只有4种),而更奇怪的是,组成DNA序列的每一种碱基在该序列中正好出现5次!这样如果一个DNA序列有N种不同的碱基构成

BZOJ1264 [AHOI2006]基因匹配Match 动态规划 树状数组

欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1264 题意概括 给出两个长度为5*n的序列,每个序列中,有1~n各5个. 求其最长公共子序列长度. 题解 我们发现这题的序列特殊性是关键! 我们只需要知道每一种数字在某一个序列中的5个位置,然后对于普通的LCS问题,我们只有在a[i] = b[j]的时候才会+1. 那么我们可以维护一个树状数组,在a序列中,我们一个一个位置扫过去,每次通过树状数组维护的前缀最大值来更新,然后因为修改不多,所以维护

BZOJ1264: [AHOI2006]基因匹配Match

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1264 因为每个字符至多出现5次,在A中记录下来.然后在B中扫一遍,因为a[i]=b[j]时f[i]++,所以维护一个树状数组记录最大值就可以了. 注意转移的顺序 #include<cstring> #include<iostream> #include<cstdio> #include<map> #include<cmath> #includ

[BZOJ1264][AHOI2006]基因匹配Match(DP + 树状数组)

传送门 有点类似LCS,可以把 a[i] 在 b 串中的位置用一个链式前向星串起来,由于链式前向星是从后往前遍历,所以可以直接搞. 状态转移方程 f[i] = max(f[j]) + 1 ( 1 <= j  < i && a[i] == b[j] ) ——代码 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 5 using namespace std; 6 7

HDU 2227 Find the nondecreasing subsequences (DP+树状数组+离散化)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2227 Find the nondecreasing subsequences                                  Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)                                             

树形DP+树状数组 HDU 5877 Weak Pair

1 //树形DP+树状数组 HDU 5877 Weak Pair 2 // 思路:用树状数组每次加k/a[i],每个节点ans+=Sum(a[i]) 表示每次加大于等于a[i]的值 3 // 这道题要离散化 4 5 #include <bits/stdc++.h> 6 using namespace std; 7 #define LL long long 8 typedef pair<int,int> pii; 9 const double inf = 12345678901234

poj 3616 Milking Time dp+树状数组

题意: 给一堆区间,每个区间有开始时间s,结束时间e,和收益w,现在要找一些区间使收益和最大,且区间之间的间隔最小为r. 分析: 这道题用dp做是简单题,用dp+树状数组做是中等题.dp问题的关键是对状态的定义.有两种方法,一:dp[k]表示按开始时间排序到第k个区间能取得的最大收益.二:dp[t]表示在时间t时能获得的最大收益.定义好状态方程就好写了这不再赘述.有趣的是这个时间复杂度.设一共有M个区间,所有区间的最大时间为L,第一种是M^2的,第二种是M*(logL+logM)的,这题M才10

奶牛抗议 DP 树状数组

奶牛抗议 DP 树状数组 USACO的题太猛了 容易想到\(DP\),设\(f[i]\)表示为在第\(i\)位时方案数,转移方程: \[ f[i]=\sum f[j]\;(j< i,sum[i]-sum[j]\ge0) \] \(O(n^2)\)过不了,考虑优化 移项得: \[ f[i]=\sum f[j]\;(j< i,sum[i]\ge sum[j]) \] 这时候我们发现相当于求在\(i\)前面并且前缀和小于\(sum[i]\)的所有和,这就可以用一个树状数组优化了,在树状数组维护下标为

BZOJ 1264: [AHOI2006]基因匹配Match( LCS )

序列最大长度2w * 5 = 10w, O(n²)的LCS会T.. LCS 只有当a[i] == b[j]时, 才能更新答案, 我们可以记录n个数在第一个序列中出现的5个位置, 然后从左往右扫第二个序列时将第一个序列对应位置的值更新, 用树状数组维护. 时间复杂度O(nlogn) ------------------------------------------------------------------------------------------------- #include<bi