题目思路:
首先得明白的是假设高度为h的时候,我们求取最少步数的方法是:max(∑(Hi−h),∑(h−Hj))(Hi>h,Hj≤h)
其中可以等价于
max(∑Hi−cnt(i)∗h,cnt(j)∗h−∑Hj)
用语言表达的意思就是H1(高于h的所有积木的高度相加之和)-cnt1(高于h的所有积木的堆数)*h
与H1(低于h的所有积木的高度相加之和)-cnt1(低于h的所有积木的堆数)*h
的最大值就是把这个w区间的积木堆的高度统一成h的最小步数。
根据题解的描述w区间通过最小的步数所实现的高度就是这个区间所有高度之和的平均值。但是由于这个数可能是小数,所以可能是这个数+1.
而且答案必然是平均值或者平均值+1,但假如平均值比h来的小的话,那就是平均值+1和h进行比较。
接下来的做法便是假设高为h以及平均值+1或者平均值的情况进行分别枚举。
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MAX 50005 #define lowbit(x) (x&(-x)) long long Sum[50005]; long long Cnt[50005]; long long high[100005]; long long sum[100005]; long long midS, midC; long long anh, anc; void updata(int x,int k) { //为了考虑新堆的情况。需要对零也进行计数 if (x == 0) Cnt[0]+=k; else for (int i = x; i < MAX; i += lowbit(i)) { Sum[i] += (x*k); Cnt[i]+=k; } } void query(int x) { for (int i = x; i>=0; i -= lowbit(i)) { //考虑新堆要把零的个数计算进去 midS += Sum[i]; midC += Cnt[i]; if (i == 0) break; } } int main() { long long n, w, h; while (~scanf("%lld%lld%lld", &n, &w, &h)) { memset(Sum, 0, sizeof(Sum)); memset(Cnt, 0, sizeof(Cnt)); memset(high, 0, sizeof(high)); sum[0] = 0; Cnt[0] = w; anh = 50000; anc = 0x7ffffffff; for (int i = 1; i <= n; i++) { scanf("%d", &high[i]); sum[i] = sum[i - 1] + high[i]; } if (sum[n] <w*h) { puts("-1"); continue; } for (int i = n + 1; i <= n + w; i++) { sum[i] = sum[i - 1]; } high[0] = 0; for (int i = 1; i <= n + w; i++) { int l = i - w; if (l < 0)l = 0; //维护w区间的和 //把每个堆的情况都加到树状数组里面去。 updata(high[i], 1); updata(high[l], -1); long long d = sum[i] - sum[l]; int H = d / (long long)w; if (H < h) H = h; if ((H + 1)*w <= sum[n]) { H++; midS = 0; midC = 0; //得到w区间小于H的全部和。 query(H); //得到w区间大于H的全部和 d = d - midS; long long mid = max(d - (w - midC)*H, H*midC-midS); if (anc > mid) { anh = H; anc = mid; } else if (anc==mid) if (H > anh) anh = H; H--; } midS = 0; midC = 0; //得到w区间小于H的全部和。 query(H); //得到w区间大于H的全部和 d = sum[i] - sum[l]; d = d - midS; long long mid = max(d - (w - midC)*H, H*midC-midS); if (anc > mid) { anh = H; anc = mid; } else if (anc == mid) if (H > anh) anh = H; } printf("%lld %lld\n", anh, anc); } return 0; }
max(∑Hi−cnt(i)∗h,cnt(j)∗h−∑Hj)
max(∑Hi−cnt(i)∗h,cnt(j)∗h−∑Hj)