问题描述
看完电影后,乐乐回家玩起了积木。 他已经搭好了 n堆积木,他想通过调整积木,使得其中有连续 W
堆积木具有相同的高度,同时他希望高度恰好为 H
乐乐的积木都这了,也就是说不能添加新的积木,只能移动现有的积木。 他可以把一个积木从一堆移动到另一堆或者新的一堆,但是不能移动到两堆之间。比如,一次移动之后,"3 2 3" 可以变成 "2 2 4" 或者 "3 2 2 1",但是不能变成"3 1 1 3". 请你帮他算算,需要移动的最少积木数。
输入描述
有多组测试数据,大约 100组。 第一行三个整数, n,W,H,n
表示有多少堆积木。 第二行 n
个元素,表示这 n
座积木的高度。 所有数据的范围 [1,50000]
;
输出描述
输出最少需要移动的次数,如果无法完成输出-1。
输入样例
4 3 2 1 2 3 5 4 4 4 1 2 3 4
输出样例
1 -1
Hint
样例解释:把第3座积木上的一个积木移动到第1座上,前3座积木的高度就变成了2 2 2,就得到了一个3*2(积木必须是连续的W堆)。
分析:
首先看对于一个连续的W堆,若要将其高度全变为h,我们可以计算出各个堆与h的差值,用s1累加低于h的部分,s2累加超出h的部分。则最少需要移动的次数为max(s1,s2),这是因为:使低于h的部分达到h需要s2个积木,这s2个可以从s1中补得,也可以从其他积木中获得;而使得超出h的积木达到h,需要移走s2个,这s2个可以移动到低于h的积木上,也可以移动到其他积木或者新堆中。于是取s1,s2的较大值,这样一定可以使得这连续的W堆高度均为h。
明白了这个,就可以枚举连续w堆的始末位置,求出使得当前w堆变为h所需移动次数,求其最小值即可。注意这里由于多出的部分可以移动到外侧,因此,可以在前面和后面加上积木个数为0的W堆,然后枚举。
注:得用c++提交,用g++会超时。
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[150005];
int main()
{
int i,n,w,h,sum,ans;
while(~scanf("%d%d%d",&n,&w,&h))
{
memset(a,0,sizeof(a));
for(i=1,sum=0;i<=n;++i) {scanf("%d",a+i+w);sum+=a[i+w];}
if(sum<w*h) puts("-1");
else
{
int s1=0,s2=0;
n+=w<<1;
for(i=1;i<=w;++i)
{
s1+=max(0,h-a[i]);
s2+=max(0,a[i]-h);
}
ans=max(s1,s2);
for(i=w+1;i<=n;++i)
{
s1-=max(0,h-a[i-w]);
s2-=max(0,a[i-w]-h);
s1+=max(0,h-a[i]);
s2+=max(0,a[i]-h);
ans=min(ans,max(s1,s2));
}
printf("%d\n",ans);
}
}
return 0;
}