Building Blocks Ⅱ
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 245 Accepted Submission(s): 54
Problem Description
LeLe is playing with blocks again.He wants to rebuild the blocks which he built yesterday.
LeLe wants to build piles which contains consecutive W piles with the same height and the height is not shorter than 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 and the height.
LeLe wants to build piles which contains consecutive W piles with the same height and the height is not shorter than 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 and the height.
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.
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
For each case, output two integers,the first one is
h
(indicate the height of W piles),the second one is the minimum number of blocks should LeLe move.
If there are multiple solutions output the maximal h .
If there is no solution, output "-1" (without quotes).
If there are multiple solutions output the maximal h .
If there is no solution, output "-1" (without quotes).
Sample Input
3 3 2 4 2 4 4 3 4 6 6 3 10 4 4 4 1 2 3 4
Sample Output
3 2 5 2 -1HintIn first case, LeLe moves one block from first pile to second pile and move one block from third pile to the right (out of three piles).The number of piles become 3 3 3 1, The minimum step is two. In second case, LeLe moves a block from first pile and second pile to third pile.
Source
题意:点击打开链接
题解:思路:枚举区间,然后求解每个区间的最优值。
关键在于,对于一个给定的区间,如何求最优的h值。
对于确定的区间,假设最终的高度为h,
代价是
max(∑(Hi−h),∑(h−Hj))(Hi>h,Hj≤h)
等价于
max(∑Hi−cnt(i)∗h,cnt(j)∗h−∑Hj)
(
cnt(i)
表示满足
Hi>h
的堆数,
cnt(j)
表示满足
Hj≤h
的堆数)。
∑Hi−cnt(i)∗h
关于h呈递减,
cnt(j)∗h−∑Hj
关于h呈递增。一个递减到0,一个从0开始递增,所以代价与h的函数图像是V字形的,交点处代价最小。此时
∑Hi−cnt(i)∗h=cnt(j)∗h−∑Hj,h=∑Hi+∑Hjcnt(i)+cnt(j)
,分母是总堆数W,分子是这个区间积木的总个数。h实际上就是这个区间的平均高度aver。考虑到四舍五入,答案是aver或者aver+1,当然还需要与题目给定的H做下比较,最终的方案是这3个数之一。
那么现在的问题的是对于给定的h,如何求花费。即,求大于等于h的数的个数跟和,小于h的数的个数跟和。按值建树,用线段树或树状数组维护即可。
复杂度O((n+w)*logn)
我是用树状数维护的,代码如下:
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> #include<string> #include<queue> #include<math.h> #include<stack> #include<map> #include<set> #include<stdlib.h> #include<vector> #define inff 0x3fffffff #define nn 110000 #define mod 1000000007 #define eps 1e-8 typedef __int64 LL; typedef unsigned __int64 LLU; const LL inf64=inff*(LL)inff; using namespace std; int n; LL w,H; int a[nn]; LL ans; int id; LL Tree[nn]; int num[nn]; LL sum; void init() { memset(num,0,sizeof(num)); memset(Tree,0,sizeof(Tree)); memset(a,0,sizeof(a)); ans=inf64; sum=0; } int inline lowbit(int x) { return x&(-x); } void add(int x,int val) { if(x==0) return ; for(int i=x;i<=50000;i+=lowbit(i)) { Tree[i]+=val; } } void ad(int x,int val) { x++; for(int i=x;i<=50001;i+=lowbit(i)) { num[i]+=val; } } LL getn(int x) { x++; int re=0; for(int i=x;i;i-=lowbit(i)) { re+=num[i]; } return re; } LL get(int x) { LL re=0; for(int i=x;i;i-=lowbit(i)) { re+=Tree[i]; } return re; } void qiu(int x) { if(x>50000) return ; if(x*w>sum) return ; LL ix=max(getn(x)*x-get(x),get(50000)-get(x)-(getn(50000)-getn(x))*x); if(ix<ans) { ans=ix; id=x; } else if(ix==ans) { id=max(id,x); } } void jie() { int ix=get(50000)/w; if(H>ix) { qiu(H); } else { qiu(ix); qiu(ix+1); } } void solve() { int i; for(i=1;i<=w;i++) { add(a[i],a[i]); ad(a[i],1); } jie(); for(i=w+1;;i++) { ad(a[i-w],-1); add(a[i-w],-a[i-w]); add(a[i],a[i]); ad(a[i],1); jie(); if(i-w>=n) break; } } int main() { int i; while(scanf("%d%I64d%I64d",&n,&w,&H)!=EOF) { init(); for(i=1;i<=n;i++) { scanf("%d",&a[i]); sum+=a[i]; } if(sum<w*H) { puts("-1"); continue; } solve(); for(i=1;i<=n/2;i++) { swap(a[i],a[n-i+1]); } memset(Tree,0,sizeof(Tree)); memset(num,0,sizeof(num)); solve(); printf("%d %I64d\n",id,ans); } return 0; }