题目描述
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 的查询,那样总时间复杂度为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;
}
你可能会注意到一件事:反着做时,只会删除栈中元素,却不会再加。对此,起初我对于它的正确性抱有疑问。后来仔细一想,其实这是十分正确的。因为如果当前这个数比上次弹出的元素小,那么之前比这个大的数必然构成了更优解,不必回头把它加回来。