luogu3503[POI2010]KLO-Blocks

探讨了一种通过重新排列相同大小的木块堆,以最大化连续堆高度至少为给定数值的堆数量的算法。该问题限制了移动方式,仅允许从较高的堆顶取一块并放置到相邻的堆上。解决方案采用预处理和双遍历单调栈的方法,以高效地解决询问。

题目描述
Bytie has got a set of wooden blocks for his birthday.
The blocks are indistinguishable from one another, as they are all cubes of the same size.

Bytie forms piles by putting one block atop another.
Soon he had a whole rank of such piles, one next to another in a straight line.

Of course, the piles can have different heights.

Bytie’s father, Byteasar, gave his son a puzzle.

He gave him a number and asked to rearrange the blocks in such a way that the number of successive piles of height at least is maximised.

However, Bytie is only ever allowed to pick the top block from a pile strictly higher than and place it atop one of the piles next to it.

Further, Bytie is not allowed to form new piles, he can only move blocks between those already existing.

给出N个正整数a[1…N],再给出一个正整数k,现在可以进行如下操作:每次选择一个大于k的正整数a[i],将a[i]减去1,选择a[i-1]或a[i+1]中的一个加上1。经过一定次数的操作后,问最大能够选出多长的一个连续子序列,使得这个子序列的每个数都不小于k。M组询问

输入格式
In the first line of the standard input there are two integers separated by a single space:

(), denoting the number of piles, and (), denoting the number of Byteasar’s requests.

The piles are numbered from to .

In the second line there are integers separated by single spaces ().

The number denotes the height of the -th pile.

The third line holds ![](http://main.edu.pl

输出格式
Your program should print out integers, separated by single spaces, to the standard output - the -th of which should be the answer to the puzzle for the given initial piles set-up and the parameter .

输入输出样例
输入 #1 复制
5 6
1 2 1 1 5
1 2 3 4 5 6
输出 #1 复制
5 5 2 1 1 0

数据范围:n<=1e6 m<=50 a[i]<=1e8

题目大意就是给你一串数,你所要做的就是对于每一个询问给出的x,回答出 ∑ i = k k + l e n − 1 a [ i ] &gt; = l e n ∗ x \sum^{k+len-1}_{i=k} a[i]&gt;=len*x i=kk+len1a[i]>=lenx的最大的len

最开始的预处理相信大家都想得到,把每个a[i]都减去x,这样只需要判断一段连续的数之和是否大于零。这时可以看出第二步预处理前缀和。问题转化成了求 s [ k + l e n − 1 ] − s [ k ] &gt; = 0 s[k+len-1]-s[k]&gt;=0 s[k+len1]s[k]>=0其中len的最大值。这题有一个很巧妙的思路。我最开始想到了单调栈,但又发觉每次查询又需要用lower_bound进行O(logn)的查询,那样总时间复杂度为O(m * n * logn)。洛谷上的巨佬ysy20021208的题解给了我很大的启发。这题实际上需要正着建一遍栈,然后逆着跑一遍。一些细节在程序后解释。先附上代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000005;
int n,m,i,j,t,k,s,a[maxn],sta[maxn];
long long b[maxn];

int main()
{
	scanf("%d%d",&n,&m);
	for (i=1;i<=n;++i) scanf("%d",&a[i]);
	while (m--)
	{
		scanf("%d",&t);
		k=1;sta[1]=0;
		for (i=1;i<=n;++i)
		{
			b[i]=a[i]-t;
			b[i]+=b[i-1];
			if (b[i]<b[sta[k]]) sta[++k]=i;
		}
		s=0;
		for (i=n;i>0;--i)
		{
			while (b[i]-b[sta[k]]>=0&&k) --k;
			s=max(s,i-sta[k+1]);
		}
		printf("%d%c",s,(m==0) ? '\n' : ' ');
	}
	return 0;
}

你可能会注意到一件事:反着做时,只会删除栈中元素,却不会再加。对此,起初我对于它的正确性抱有疑问。后来仔细一想,其实这是十分正确的。因为如果当前这个数比上次弹出的元素小,那么之前比这个大的数必然构成了更优解,不必回头把它加回来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值