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

题目描述

Mary在她的生日礼物中有一些积木。那些积木都是相同大小的立方体。每个积木上面都有一个数。Mary用他的所有积木垒了一个高塔。妈妈告诉Mary游戏的目的是建一个塔,使得最多的积木在正确的位置。一个上面写有数i的积木的正确位置是这个塔从下往上数第i个位置。Mary决定从现有的高塔中移走一些,使得有最多的积木在正确的位置。请你告诉Mary她应该移走哪些积木。

输入

第一行为一个数n,表示高塔的初始高度。第二行包含n个数a1,a2,...,an,表示从下到上每个积木上面的数。

输出

注意:请输出最多有多少点可以处在正确位置

样例输入

5
1 1 2 5 4

样例输出

3



题解

动态规划+树状数组

设f[i]表示在前i个积木中选择i最多有多少点处在正确位置。

那么如果j能够更新i,需要满足条件:$j<i\ \&\&\ a_j<a_i\ \&\&\ a_i-a_j\le i-j(j-a_j\le i-a_i)$。

这看似是三个条件的三维偏序问题,而实际上由后两个条件可以推出第一个条件,可以忽略,就变成了二维偏序问题。

那么就可以按照a值从小到大排序,就变为了最长不下降子序列问题。可以用树状数组来维护。

注意:由于要求$a_j$要严格小于$a_i$,所以当它们相等时不应进行更新。这里为了避免这个问题,将$a_i$相等的i按照$i-a_i$从大到小排序,防止多余的更新。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
using namespace std;
struct data
{
	int x , y;
}a[N];
int v[N] , tot , f[N] , dp[N] , n;
bool cmp1(data a , data b)
{
	return a.y < b.y;
}
bool cmp2(data a , data b)
{
	return a.x == b.x ? a.y > b.y : a.x < b.x;
}
void update(int x , int a)
{
	int i;
	for(i = x ; i <= tot ; i += i & -i) f[i] = max(f[i] , a);
}
int query(int x)
{
	int i , ans = 0x80000000;
	for(i = x ; i ; i -= i & -i) ans = max(ans , f[i]);
	return ans;
}
int main()
{
	int i , ans = 0;
	scanf("%d" , &n) , n ++ , a[1].y = 1;
	for(i = 2 ; i <= n ; i ++ ) scanf("%d" , &a[i].x) , a[i].y = i - a[i].x;
	sort(a + 1 , a + n + 1 , cmp1) , v[0] = 0x80000000;
	for(i = 1 ; i <= n ; i ++ )
	{
		if(a[i].y != v[tot]) v[++tot] = a[i].y;
		a[i].y = tot;
	}
	sort(a + 1 , a + n + 1 , cmp2);
	memset(f , 0x80 , sizeof(f)) , update(a[1].y , 0);
	for(i = 2 ; i <= n ; i ++ ) dp[i] = query(a[i].y) + 1 , update(a[i].y , dp[i]) , ans = max(ans , dp[i]);
	printf("%d\n" , ans);
	return 0;
}
时间: 2024-10-04 11:33:38

【bzoj1109】[POI2007]堆积木Klo 动态规划+树状数组的相关文章

BZOJ1109 : [POI2007]堆积木Klo

f[i]表示第i个在自己位置上的最大值 则f[i]=max(f[j])+1 其中 j<i a[j]<a[i] a[i]-a[j]<=i-j -> j-a[j]<=i-a[i] i-a[i]>=0 j-a[j]>=0 发现后两项可以推出第一项,所以是一个LIS问题,排序后树状数组优化DP即可,时间复杂度$O(n\log n)$. #include<cstdio> #include<algorithm> #define N 100010 int

[POI2007]堆积木Klo

Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 530  Solved: 172[Submit][Status] Description Mary在她的生日礼物中有一些积木.那些积木都是相同大小的立方体.每个积木上面都有一个数.Mary用他的所有积木垒了一个高塔.妈妈告诉Mary游戏的目的是建一个塔,使得最多的积木在正确的位置.一个上面写有数i的积木的正确位置是这个塔从下往上数第i个位置.Mary决定从现有的高塔中移走一些,使得有最多的积木在正确的

【BZOJ1109】[POI2007]堆积木Klo 二维偏序

[BZOJ1109][POI2007]堆积木Klo Description Mary在她的生日礼物中有一些积木.那些积木都是相同大小的立方体.每个积木上面都有一个数.Mary用他的所有积木垒了一个高塔.妈妈告诉Mary游戏的目的是建一个塔,使得最多的积木在正确的位置.一个上面写有数i的积木的正确位置是这个塔从下往上数第i个位置.Mary决定从现有的高塔中移走一些,使得有最多的积木在正确的位置.请你告诉Mary她应该移走哪些积木. Input 第一行为一个数n,表示高塔的初始高度.第二行包含n个数

BZOJ 1109: [POI2007]堆积木Klo

Sol 排序+树状数组. 我们要找一个满足下列条件的最长序列. \(j-w[j]<=i-w[i],j<i,w[j]<w[i]\) 就是维护一个偏序集的最长上升子序列,然后第一个和第三个式子加起来可以推出第二个式子,然后就是二维偏序,用树状数组来维护就可以了. Code /************************************************************** Problem: 1109 User: BeiYu Language: C++ Result:

[bzoj1103][POI2007]大都市meg_dfs序_树状数组

大都市meg bzoj-1103 POI-2007 题目大意:给定一颗n个点的树,m次操作.将一条路的边权更改成0:查询一个点到根节点的点权和.开始的时候所有边的边权都是1. 注释:$1\le n,m\le 2.5\cdot 10^5$. 想法:我们先拉出dfs序.其实严格来讲是出栈入栈序,就是每个点在序上出现两次的那个. 开始的时候入栈时的点权是1,出栈是-1.修改就是把出栈入栈都改成0.然后用树状数组查询前缀和即可. 最后,附上丑陋的代码... ... #include <iostream>

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

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

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)

【BZOJ4361】isn 动态规划+树状数组+容斥

[BZOJ4361]isn Description 给出一个长度为n的序列A(A1,A2...AN).如果序列A不是非降的,你必须从中删去一个数, 这一操作,直到A非降为止.求有多少种不同的操作方案,答案模10^9+7. Input 第一行一个整数n. 接下来一行n个整数,描述A. Output 一行一个整数,描述答案. Sample Input 4 1 7 5 3 Sample Output 18 HINT 1<=N<=2000 题解:想到动归+树状数组+容斥,但是容斥系数想复杂了~ 我们希

#46 delete(动态规划+树状数组)

二维的dp非常显然,但这也没有什么优化的余地了. 注意到最后的方案中只有产生贡献的位置是有用的,剩下的部分可以在该范围内任意选取. 所以我们考虑设f[i]为i号位最后产生贡献的答案,则f[i]=max{f[j]+1} (i-j>=a[i]-a[j],a[i]>a[j]). 观察这个限制,即为i-a[i]>=j-a[j]且a[i]>a[j],以及i>j.可以发现这里i>j的限制是可以被前两个限制所包含的.于是我们考虑换个顺序dp,按照a[i]从小到大来.树状数组维护即可.