http://acm.hdu.edu.cn/showproblem.php?pid=5191
比较fanjian的题目。。。因为G++交的话就会TLE。。。据说是HDU换了C11的编译器问题百出?
注意题目描述非常不清楚,不光可以把方块放在最右边的空地,也可以放在最左边的空地!!!我就是这样WA的!!!
因此我们在得到每堆方块的高度后,在所有方块的左边放W个高度为0的方块,右边放W个高度为0的方块。然后就是用两个指针维护一段长度为W的连续方块区间,并检查这段区间里的所有方块堆都变成高度为H的话最少要移动多少次,最优做法一定是先在这段区间内调整,高度大于H的堆往高度小于H的堆移动方块,然后再把还差的方块从外面移动进这段区间,或把还多的方块移动到外面。
其中需要对两个东西进行求和,可以维护这两个区间和的值,或者预处理出前缀和,均可以在每次移动区间后O(1)求得。
1、前缀和版本
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXN 160000
using namespace std;
typedef long long int LL;
inline LL mymin(LL a,LL b)
{
if(a>b) return b;
return a;
}
inline LL myabs(LL x)
{
if(x>0) return x;
return -x;
}
LL h[MAXN],ans[MAXN],sum[MAXN];
int main()
{
int n,W,H;
while(scanf("%d%d%d",&n,&W,&H)!=EOF)
{
memset(h,0,sizeof(h));
memset(ans,0,sizeof(ans));
memset(sum,0,sizeof(sum));
LL summ=0;
for(int i=W+1;i<=n+W;i++)
{
scanf("%lld",&h[i]);
summ+=h[i];
}
if(H*W>summ)
{
printf("-1\n");
continue;
}
for(int i=1;i<=n+2*W;i++)
{
ans[i]=ans[i-1]+myabs(h[i]-H);
sum[i]=sum[i-1]+h[i];
}
LL minans=0x7fffffff;
for(int head=1,tail=W;tail<=2*W+n;head++,tail++)
{
LL anss=(ans[tail]-ans[head-1]+myabs(sum[tail]-sum[head-1]-H*W))/2;
minans=mymin(minans,anss);
}
if(minans==0x7fffffff)
{
printf("-1\n");
continue;
}
printf("%lld\n",minans);
}
return 0;
}
2、维护区间和的值版本
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXN 160000
using namespace std;
typedef long long int LL;
LL h[MAXN],ans[MAXN],sum[MAXN];
inline LL mymin(LL a,LL b)
{
if(a>b) return b;
return a;
}
inline LL myabs(LL x)
{
if(x>0) return x;
return -x;
}
int main()
{
int n,W,H;
while(scanf("%d%d%d",&n,&W,&H)!=EOF)
{
memset(h,0,sizeof(h));
LL summ=0;
for(int i=W+1;i<=n+W;i++)
{
scanf("%lld",&h[i]);
summ+=h[i];
}
if(H*W>summ)
{
printf("-1\n");
continue;
}
/*for(int i=1;i<=n+2*W;i++) { ans[i]=ans[i-1]+abs(h[i]-H); sum[i]=sum[i-1]+h[i]; }*/
int head=1,tail=W,ans=0,sum=0;
for(int i=head;i<=tail;i++)
{
ans+=myabs(h[i]-H);
sum+=h[i];
}
LL minans=0x7fffffff;
for(;tail<=2*W+n;head++,tail++)
{
LL anss=(ans+myabs(sum-H*W))/2;
minans=mymin(minans,anss);
ans-=myabs(h[head]-H);
ans+=myabs(h[tail+1]-H);
sum-=h[head];
sum+=h[tail+1];
}
if(minans==0x7fffffff)
{
printf("-1\n");
continue;
}
printf("%lld\n",minans);
}
return 0;
}