Codeforces Round #352 (Div. 2) D. Robin Hood

题目连接请戳此处

题意:n个人每人有一定的财富值ci,每天Robin Hood从最富的人手中取财富1分给最穷的人(取后最穷,

即可以退回),若有多个最穷的人,任选一个给出财富值。问k天后最富的人和最穷的人财富差值为多少。

1 ≤ n ≤ 500 000, 0 ≤ k ≤ 109

1 ≤ ci ≤ 109

 

分析:

每一天随着财富值的取和给,最穷的人和最富的人都在动态更新。

最后要求的是  (richest-poorest)min,那么  要使这个等式最小,只需求出k天后richest的最小值和poorest

最大值即可。由于富人的财富是单调递减的,穷人的财富是单调递增的。那么二分枚举就可以找到这两个值。

枚举的左右端点 保守点选择L=1,R=1e9。这样复杂度大概是log2(109)约为log2(230)=30。

当poorest(max)<richest(min),ans = richest(min) - poorest(max);

否则,即出现了穷人变富人,富人变穷人,说明中间肯定有某天d<k使得财富值相等或者相差1。

这时ans = sum%n==0?0:1。

 

需要注意是中间过程 可能会爆int,最好全用longlong

1e9表示109。这个e表示小数点移动几位。

C中的常量,后缀缺省时,整数的类型为int,浮点数的类型为double。

所以使用时,若常量需要为long long ,则应该在后面加LL后缀。

 

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>

using namespace std;

typedef long long ll;

ll c[500005],sum,n;

ll cal1(ll x)
{
    ll sum = 0;
    for(int i=0;i<n;i++)
    {
        if(c[i]>x)
            sum += (c[i]-x);
    }
    return sum;
}
ll cal2(ll x)
{
    ll sum = 0;
    for(int i=0;i<n;i++)
    {
        if(c[i]<x)
            sum += (x-c[i]);
    }
    return sum;
}

int main()
{
    ll k;
    while(~scanf("%I64d%I64d",&n,&k))
    {
        sum = 0;
        for(int i=0;i<n;i++)
        {
            scanf("%I64d",&c[i]);
            sum += c[i];
        }
        sort(c,c+n);
        ll l = 1,r = 1e9;
        ll rich,poor,mid;
        while(l<r)
        {
            mid = l+(r-l)/2;
            if(cal1(mid)<=k)
            {
                rich = mid;
                r = mid;
            }
            else l = mid+1;
        }
        l = 1,r = 1e9;
        while(l<r)
        {
            mid = l+(r-l)/2;
            if(cal2(mid)<=k)
            {
                poor = mid;
                l = mid+1;
            }
            else r = mid;
        }
        if(poor<rich) printf("%I64d\n",rich-poor);
        else printf("%d\n",sum%n == 0?0:1);
    }
    return 0;
}

 

posted @ 2016-05-27 20:09  fukan  阅读(200)  评论(0编辑  收藏  举报