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; }