hdu 5191 Building Blocks

来源:互联网 发布:winhex linux 编辑:程序博客网 时间:2024/05/15 02:39
问题描述
看完电影后,乐乐回家玩起了积木。他已经搭好了n堆积木,他想通过调整积木,使得其中有连续W堆积木具有相同的高度,同时他希望高度恰好为H乐乐的积木都这了,也就是说不能添加新的积木,只能移动现有的积木。他可以把一个积木从一堆移动到另一堆或者新的一堆,但是不能移动到两堆之间。比如,一次移动之后,"3 2 3" 可以变成 "2 2 4" 或者 "3 2 2 1",但是不能变成"3 1 1 3".请你帮他算算,需要移动的最少积木数。
输入描述
有多组测试数据,大约100组。第一行三个整数,nWHn表示有多少堆积木。第二行n个元素,表示这n座积木的高度。所有数据的范围[1,50000];
输出描述
输出最少需要移动的次数,如果无法完成输出-1。
输入样例
4 3 21 2 3 54 4 41 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;}


 

0 0
原创粉丝点击