hdu5192 BC#34 树状数组维护

来源:互联网 发布:淘宝上买手机是正品吗 编辑:程序博客网 时间:2024/06/06 19:06

问题描述
乐乐又开始搭积木了。他想在昨天搭完的积木上,重新搭建,使得其中有连续W堆积木具有相同的高度,同时他希望高度最少为H。乐乐的积木都这了,也就是说不能添加新的积木,只能移动现有的积木。他可以把一个积木从一堆移动到另一堆或者新的一堆,但是不能移动到两堆之间。比如,一次移动之后,"3 2 3" 可以变成 "2 2 4" 或者 "3 2 2 1",但是不能变成"3 1 1 3".请你帮他算算,当搭建的高度h为多少时,需要移动的积木最少,如果有多个h满足条件,输出h的最大值。 
输入描述
有多组数据,大约100组。对于每组数据,第一行三个整数nWH。第二行n个元素,表示n座积木的高度。题目中所有数据的范围[1,50000];
输出描述
输出两个整数,第一个数表示搭建的高度h,第二个数表示需要移动的最小积木数。如果有多个h满足使得移动步数最少,输出h的最大值。如果不能形成高度最少为H的连续的W堆积木,输出-1。
输入样例
3 3 24 2 44 3 46 6 3 104 4 41 2 3 4
输出样例
3 25 2-1
Hint
样例一解释,一种可行的方案是从第一堆移动一个到第二堆,从第三堆上面移动一个放到右边,每堆个数变成 3 3 3 1。最少移动2次。样例二解释,把第一座和第二座积木上的一个积木移动到第三座积木上,得到3*5。

思路:大致想法和5191类似。但每个区间的h是不同的。比较容易想到,合适的h是这个区间的平均数(如果h<给定的下限hl,则为hl)。但是朴素的方法,在算每个区间小于h和大于h的和时,会是O(n^2)的,肯定不行,因此我们需要用到树状数组维护。维护的方法,对于树状数组用的少人(比如我...)来说不好想到...其实这里维护的是所有高度的可能值,而不是数组序列。这种方法类似于用树状数组维护逆序对个数(具体方法详见我另外的博文),另外也用到区间修改,查询点的思想(即加一个,减一个)...我这里用了两个树状数组维护区间内,<=h的元素个数和<=h的元素的总和,再通过区间内总共有w个元素且区间内元素总和,算出大于h的这两个值。

注意:(1)每次的平均数不能直接四舍五入...两边都要算一下!!(被这个点WA了一晚上加一早上...)

   (2)树状数组中的n要注意是maxh!别随手一打就写成n了....

   (3)h还有上界,算平均数上取整的时候是有可能超过这个上界的!

代码中间有些调整,导致写的有些乱...不要介意。。。


#include <iostream>#include <cmath>#include <stdio.h>#include <vector>#include <queue>#include <algorithm>#include <cstring>#include <string>#include <cstdlib>#include <map>using namespace std;#define I64_MAX 9223372036854775807 typedef long long ll;const double pi=acos (-1.0);const long double eps=1e-15 ;const ll INF=(I64_MAX)/2;//#pragma comment(linker, "/STACK:102400000,102400000")const int inf=0x3f3f3f3f ;#define maxx(a) memset(a, 0x3f, sizeof(a))#define zero(a) memset(a, 0, sizeof(a))#define FILL(a,b) memset(a, b, sizeof(a))#define REP(i,a,b) for(i=a;i<b;i++)#define rep(i,n) REP(i,0,n)#define srep(i,n) for(i = 1;i <= n;i ++)#define snuke(c,itr) for( __typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)#define MP make_pair#define fi first#define se secondtypedef pair <int, int> PII;typedef pair <ll, ll> PX;typedef pair<int,ll> PIL;#define MAX 200000const int maxh = 50005;int n,m,w;ll hl,hh;int a[MAX];ll tree[2][maxh];ll qian[MAX];inline int lowbit(int x){return x&(-x);}void update(int i,ll x,int j){//因为索引不能有0 i++;while(i <= maxh){tree[j][i] += x;i += lowbit(i);}}ll query(int i,int j){i++;ll ret = 0;while(i>0){ret += tree[j][i];i -= lowbit(i); }return ret; }int main (){     //freopen("E:\\in.txt" ,"r", stdin);     // freopen ("E:\\out.txt","w",stdout);int i,j;while(scanf("%d%d%lld",&n,&w,&hl)==3){ll sum = 0;memset(tree,0,sizeof(tree));memset(qian,0,sizeof(qian));memset(a,0,sizeof(a));for(i=w;i<w+n;i++){scanf("%d",&a[i]);sum += (ll)a[i];}if(sum < (ll)w*hl){puts("-1");continue;}hh = sum / (ll)w;n = w+w+n;sum = 0;for(i = w;i<n;i++){sum -= (ll)a[i-w];sum += (ll)a[i];qian[i] = sum;}ll ans = (ll)w*hl;ll ansh = hl;ll high,low;update(0,(ll)w,0);for(i=w;i<n;i++){update(a[i-w],(ll)-1,0);update(a[i],(ll)1,0);update(a[i-w],(ll)-a[i-w],1);update(a[i],(ll)a[i],1); ll h1 = (ll)((long double)qian[i] / (long double)w  + eps);h1 = max(hl,h1);h1 = min(h1,hh);ll tmp1 = query((int)h1,0);ll tmp2 = query((int)h1,1);low = tmp1*h1 - tmp2;high =  qian[i] - tmp2 -  (w - tmp1) * h1;low = max(low,high);if(low < ans){ans = low;ansh = h1;}else if(low == ans && h1 > ansh){ansh = h1;}h1 = (ll)((long double)qian[i] / (long double)w  + eps) + 1;h1 = max(hl,h1);h1 = min(h1,hh);tmp1 = query((int)h1,0);tmp2 = query((int)h1,1);low = tmp1*h1 - tmp2;high =  qian[i] - tmp2 -  (w - tmp1) * h1;low = max(low,high);if(low < ans){ans = low;ansh = h1;}else if(low == ans && h1 > ansh){ansh = h1;}}printf("%lld %lld\n",ansh,ans);}return 0;}


0 0
原创粉丝点击