hdu 5191 Building Blocks

问题描述
看完电影后,乐乐回家玩起了积木。
他已经搭好了
  
  
   
   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 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;
}


 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值