BZOJ 1264 AHOI2006 基因匹配Match 动态规划+树状数组

题目大意:给定n个数和两个长度为n*5的序列,每个数恰好出现5次,求两个序列的LCS

n<=20000,序列长度就是10W,朴素的O(n^2)一定会超时

所以我们考虑LCS的一些性质

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)

很难想的一道题 不过不难写

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 200200
using namespace std;
int n,ans,a[M*5],b[M*5],c[M*5],f[M*5],pos[M][6];
void Update(int x,int y)
{
	for(;x<=n*5;x+=x&-x)
		c[x]=max(c[x],y);
}
int Get_Ans(int x)
{
	int re=0;
	for(;x;x-=x&-x)
		re=max(re,c[x]);
	return re;
}
int main()
{
	int i,j;
	cin>>n;
	for(i=1;i<=n*5;i++)
	{
		scanf("%d",&a[i]);
		pos[ a[i] ][ ++pos[a[i]][0] ]=i;
	}
	for(i=1;i<=n*5;i++)
		scanf("%d",&b[i]);
	for(i=1;i<=n*5;i++)
	{
		for(j=5;j;j--)
		{
			int k=pos[b[i]][j];
			f[k]=max( f[k] , Get_Ans(k-1)+1 );
			Update(k,f[k]);
			ans=max(ans,f[k]);
		}
	}
	cout<<ans<<endl;
}
时间: 2024-10-12 23:51:40

BZOJ 1264 AHOI2006 基因匹配Match 动态规划+树状数组的相关文章

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

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

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

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

bzoj 1264: [AHOI2006]基因匹配Match (树状数组优化dp)

链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1264 思路: n大小为20000*5,而一般的dp求最长公共子序列复杂度是 n*n的,所以我们必须优化. 题目说了一个数会出现5次,那么我们可以预处理得到 第一个序列a[]每个数字分别在哪些位置, 因为求LCS的状态转移方程中当 s1[i-1] == s2[j-1]时,dp[i][j] = dp[i-1][j-1] + 1;只有当两个点相同时 值才会+1,我们可以对第二个序列b[]遍历一遍

BZOJ 1264 [AHOI2006]基因匹配Match

有一定思维难度的题目..看了mps大爷的题解才会做(%%% mps) 考虑暴力O(n^2)dp的算法,只有当A[i] == B[j]时才会+1.我们可以利用这个性质,记录下每个数在A[i]中的5个位置.然后从前往后扫描B,顺便转移.转移时要维护前缀max,这个可以用树状数组随意维护一下.时间复杂度是O(nlogn)的 具体看代码 1 //F[i]表示B与A中前i个数的LCS长度 2 3 #include <cstdio> 4 #include <algorithm> 5 6 usi

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种不同的碱基构成

BZOJ 1452: [JSOI2009]Count (二维树状数组)

Description Input Output Sample Input Sample Output 1 2 HINT 二维树状数组的简单应用,c数组的第一维坐标相当于哈希.如果是修改操作,修改前 将当前的值的个数以及祖先都减1, 修改后将个数加1. #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <set> #include

【bzoj1109】[POI2007]堆积木Klo 动态规划+树状数组

题目描述 Mary在她的生日礼物中有一些积木.那些积木都是相同大小的立方体.每个积木上面都有一个数.Mary用他的所有积木垒了一个高塔.妈妈告诉Mary游戏的目的是建一个塔,使得最多的积木在正确的位置.一个上面写有数i的积木的正确位置是这个塔从下往上数第i个位置.Mary决定从现有的高塔中移走一些,使得有最多的积木在正确的位置.请你告诉Mary她应该移走哪些积木. 输入 第一行为一个数n,表示高塔的初始高度.第二行包含n个数a1,a2,...,an,表示从下到上每个积木上面的数. 输出 注意:请

【BZOJ】1012: [JSOI2008]最大数maxnumber(树状数组+区间最值)

http://www.lydsy.com/JudgeOnline/problem.php?id=1012 树状数组原来我只懂得sum和add的操作,今天才知道可以有求区间最值的操作,我学习了一下写了个,1a了. 区间最值其实和区间求和差不多,就是将sum数组的含义转移到max,然后通过特定的区间更新max. 在区间求和中,当我们维护max[i]的时候,要找到它前面所有的max[j]来更新,在这里因为是树状数组,所以可以降成一个log级,画图可知,max[i]需要的max只有max[i-2^0],

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