Building Blocks 区间枚举

Building Blocks
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1182 Accepted Submission(s): 262


Problem Description
After enjoying the movie,LeLe went home alone. LeLe decided to build blocks.
LeLe has already built n piles. He wants to move some blocks to make W consecutive piles with exactly the same height H.

LeLe already put all of his blocks in these piles, which means he can not add any blocks into them. Besides, he can move a block from one pile to another or a new one,but not the position betweens two piles already exists.For instance,after one move,"3 2 3" can become "2 2 4" or "3 2 2 1",but not "3 1 1 3".

You are request to calculate the minimum blocks should LeLe move.


Input
There are multiple test cases, about 100 cases.

The first line of input contains three integers n,W,H(1≤n,W,H≤50000).n indicate n piles blocks.

For the next line ,there are n integers A1,A2,A3,……,An indicate the height of each piles. (1≤Ai≤50000)

The height of a block is 1.


Output
Output the minimum number of blocks should LeLe move.

If there is no solution, output "-1" (without quotes).


Sample Input

4 3 2 1 2 3 5 4 4 4 1 2 3 4



Sample Output

1 -1
Hint

In first case, LeLe move one block from third pile to first pile.


枚举最终的W堆积木在哪,确定了区间,那么就需要把高于H的拿走,低于H的补上,高处的积木放到矮的上面,这样最优。因此把这个区间变成W*H的代价就是max(∑(Hi−H),∑(H−Hj))(Hi>H,Hj≤H)即在把高的变矮和把矮的变高需要的移动的积木数
取较大的。从第一个区间[1,W]到第二区间[2,W+1]只是改变了2堆积木,可以直接对这两堆积木进行删除和添加来维护∑(Hi−H)和∑(H−Hj)。
需要注意的是,最终选取的W堆积木中,有可能有几堆原本不存在。如 9 8 7 形成3*3,可把3堆积木变成5堆 3 3 3 8 7,最少移动6个积木。因此需要在n堆积木两端补上W个0。整个问题的复杂度是O(n+W).

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<map>
using namespace std;
const int maxn=50005*3;
const int inf=200000;
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r

template<class T>inline T read(T&x)
{
    char c;
    while((c=getchar())<=32);
    bool ok=false;
    if(c=='-')ok=true,c=getchar();
    for(x=0; c>32; c=getchar())
        x=x*10+c-'0';
    if(ok)x=-x;
    return x;
}
template<class T> inline void write(T x)
{
    if(x<0)putchar('-'),x=-x;
    if(x<10)putchar(x+'0');
    else write(x/10),putchar(x%10+'0');
}
template<class T>inline void writeln(T x)
{
    write(x);
    putchar('\n');
}
///-------IO template------
int a[maxn];
typedef long long ll;
int main()
{
    int n,m,i,j,k,t;
    int w,h;
    while(~scanf("%d%d%d",&n,&w,&h))
    {
        ll sum=0;
        for(i=1;i<=w;i++)a[i]=0;
        for(i=w+1; i<=n+w; i++)
        {
            read(a[i]);
            sum+=a[i];
        }
        for(i=n+w+1;i<=n+w+w;i++)a[i]=0;
        if(sum<(ll)w*h)
        {
            printf("-1\n");
            continue;
        }
        ll ans2=0;
        ll ans1=0;
        ll ans=inf,rec=inf;
        for(i=1; i<=w; i++)
        {
            if(a[i]>h)
                ans1+=a[i]-h;
            else
                ans2+=h-a[i];
        }
        int first=1;
        rec=ans=max(ans1,ans2);
        for(i=w+1; i<=n+w+w; i++)
        {
            if(a[first]>h)
                ans1-=a[first]-h;
            else
                ans2-=h-a[first];

            if(a[i]>h)
                ans1+=a[i]-h;
            else
                ans2+=h-a[i];
            first++;
        ans=max(ans1,ans2);
        rec=min(ans,rec);
        }
        writeln(rec);
    }
    return 0;
}







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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值