BZOJ 1264 浅谈数据结构优化特殊形式LCS动态规划求法
2017-09-27 20:42
337 查看
世界真的很大
DP复习中顺便搞一下数据结构
但这道题其实不是非常典型,并不是一般的DP,只是思路巧妙罢了
代码不是很难
算是复习一下LCS的DP求法吧,毕竟学了这么久了
看题先:
description:
基因匹配(match) 卡卡昨天晚上做梦梦见他和可可来到了另外一个星球,这个星球上生物的DNA序列由无数种碱基排列而成(地球上只有4种),而更奇怪的是,组成DNA序列的每一种碱基在该序列中正好出现5次!这样如果一个DNA序列有N种不同的碱基构成,那么它的长度一定是5N。 卡卡醒来后向可可叙述了这个奇怪的梦,而可可这些日子正在研究生物信息学中的基因匹配问题,于是他决定为这个奇怪星球上的生物写一个简单的DNA匹配程序。 为了描述基因匹配的原理,我们需要先定义子序列的概念:若从一个DNA序列(字符串)s中任意抽取一些碱基(字符),将它们仍按在s中的顺序排列成一个新串u,则称u是s的一个子序列。对于两个DNA序列s1和s2,如果存在一个序列u同时成为s1和s2的子序列,则称u是s1和s2的公共子序列。 卡卡已知两个DNA序列s1和s2,求s1和s2的最大匹配就是指s1和s2最长公共子序列的长度。 [任务] 编写一个程序: 从输入文件中读入两个等长的DNA序列; 计算它们的最大匹配; 向输出文件打印你得到的结果。input:
输入文件中第一行有一个整数N,表示这个星球上某种生物使用了N种不同的碱基,以后将它们编号为1…N的整数。 以下还有两行,每行描述一个DNA序列:包含5N个1…N的整数,且每一个整数在对应的序列中正好出现5次。output:
输出文件中只有一个整数,即两个DNA序列的最大匹配数目首先还是解决一下LCS是何物
不是最长公共子串,而是最长公共子序列
这个东西我们一般都是有n^2的DP求法的。
如下:
#include<stdio.h> #include<cstring> #include<algorithm> using namespace std; int f[1010][1010]; char s1[1010],s2[1010]; int main() { while(scanf("%s%s",s1,s2)!=EOF) { int l1=strlen(s1),l2=strlen(s2); for(int i=1;i<=l1;i++) for(int j=1;j<=l2;j++) if(s1[i-1] == s2[j-1]) f[i][j]=f[i-1][j-1]+1; else f[i][j]=max(f[i-1][j],f[i][j-1]); printf("%d\n",f[l1][l2]); memset(f,0,sizeof(f)); } }
但是呢,这道题我们看一下数据范围就是1e5,n^2不可做。
但是明确一点,单单LCS的话是没有比n^2更优的做法了
那么很显然肯定要利用题目性质
那么自然,题目中说“每个数只出现5次“会映入眼帘
分析一下上述LCS的动态规划方程,LCSdp方程的值的改变只是会出现在 s1[i] == s2[j]的地方,而其余情况都是直接由之前状态转移得来
那么,考虑b数组的每一个位置,其能更新的答案只有与其相同的数字的a数组的答案而已,其余的递推转移都只是。。无操作
但在一般的LCS里,我们无法得知与这个位置相同的a数组是哪些位置,所以需要去for
但反观这道题,每个数只有5个,那么对于每个数只会出现5次,我们就可以记录这些出现的位置,然后每一个b都只是去更新这些位置的答案
所以说我们的思路就出来了,对于找到的每一个b,我们找到其在a中的所有位置,记f(i)表示到a的第i位为止的LCS,然后找到其前面所有的f的最大值+1来更新答案。
即使我们都到了这一步,发现要想用前面的最大值来更新答案竟然还是n^2的。。。
现在的情况是,f(i)的答案由其前面所有的f值的最值得到,也就是所谓的”填表法“,这时我们就可以考虑用数据结构优化转移,而数据结构能有化的,也只有”转移“,而没有“更新”
还有需要注意的地方
枚举位置注意倒着枚举,从5到1。
因为当前bi只能转移一个位置,而如果先枚举前面的就很有可能使得后面枚举查询时最值改变
完整代码:
#include<stdio.h> #include<algorithm> using namespace std; struct node { int sum; node *ls,*rs; void update() { sum=max(ls->sum,rs->sum); } }pool[2000010],*tail=pool,*root; int n,pos[100010][6],top[100010],f[100010],ans=0; node *build(int lf,int rg) { node *nd=++tail; if(lf==rg) { nd->sum=0; nd->ls=nd->rs=0; return nd; } int mid=(lf+rg)>>1; nd->ls=build(lf,mid); nd->rs=build(mid+1,rg); return nd; } void modify(node *nd,int lf,int rg,int pos,int delta) { if(lf==rg) { nd->sum=delta; return ; } int mid=(lf+rg)>>1; if(pos<=mid) modify(nd->ls,lf,mid,pos,delta); else modify(nd->rs,mid+1,rg,pos,delta); nd->update(); } int query(node *nd,int lf,int rg,int L,int R) { if(L<=lf && rg<=R) return nd->sum; int mid=(lf+rg)>>1,rt=0; if(L<=mid) rt=max(rt,query(nd->ls,lf,mid,L,R)); if(R>mid) rt=max(rt,query(nd->rs,mid+1,rg,L,R)); return rt; } int main() { scanf("%d",&n); for(int i=1;i<=5*n;i++) { int x; scanf("%d",&x); pos[x][++top[x]]=i; } root=build(0,5*n); for(int i=1;i<=5*n;i++) { int x; scanf("%d",&x); for(int j=5;j>=1;j--) { int k=pos[x][j]; f[k]=max(f[k],query(root,0,5*n,0,k-1)+1); modify(root,0,5*n,k,f[k]); ans=max(ans,f[k]); } } printf("%d\n",ans); return 0; } /* EL PSY CONGROO */
嗯,就是这样
相关文章推荐
- BZOJ 2006 浅谈数据结构优化贪心思路
- [bzoj3218] a+b problem [最小割+数据结构优化建图]
- BZOJ 1597 浅谈构造斜率--优化动态规划转移
- BZOJ 2131 数据结构优化DP 解题报告
- BZOJ 1026 浅谈特殊要求预处理数位动态规划
- HDU 4719 浅谈数据结构优化双关键字动态规划
- BZOJ_1096_[ZJOI2007]_仓库建设_(斜率优化动态规划+单调队列+特殊的前缀和技巧)
- BZOJ3790 神奇项链 解题报告【字符串】【Manacher】【树状数组】【数据结构优化DP】
- 动态规划(斜率优化):BZOJ 1010 【HNOI2008】 玩具装箱
- 数据结构(LCT动态树):BZOJ 1036: [ZJOI2008]树的统计Count
- 算法导论,动态规划 —— 最长公共子序列问题(LCS)优化python示例
- 简单来说 数据结构有哪些? 存储方式上:链表形式,数组,
- UVALive 4998 浅谈欧拉定理优化数位动态规划求解高阶同余方程
- 【数据结构】顺序表的两种存储形式
- 【动态规划24】bzoj3437小P的牧场(dp+斜率优化)
- BZOJ2427 浅谈TARJAN缩点 和 树形依赖背包动态规划
- C语言-数据结构-快速排序及优化-源代码
- 结构和其他数据形式 联合简介
- BZOJ3156 防御准备(动态规划+斜率优化)
- MySQL结构优化技术之:掌控数据的结构