CodeForces - 672D Robin Hood (思维二分)

题意

城里有 n 户人家,每户人家有 mi 个金币。robin 每天从最富的人家偷一个金币送给最穷的一户人家。问 k 天后最富的一户人家比最穷的一户人家多多少金币。

思路

首先要想明白一个问题,金币只是进行交换用的,所以金币的总数是不变的,然后我们考虑一下最终的状态,最富的人一定是一个固定的金币数,最穷的呢,也是一个固定的金币数,那么我们把从最开始最富的人的金币数记录下来,一直到最后,我们发现这个曲线一定是一个递减的,同样最穷的人的金币一定是递增的,并且最重要的一点是最富的一定大于等于金币的平均值,最穷的呢一定小于等于平均值,这样最富最穷的范围就出来了,然而它们的变化趋势也有了,这样我们就可以根据递增递减这个性质来进行二分查找了,分别二分出最富和最穷然后做一下差就得出答案了; 注意中间变量爆int;

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define INF 0x7f7f7f7f
const int maxed = 500000 + 10;
typedef long long ll;
ll n, m, p[maxed];
int main()
{
    scanf("%lld%lld", &n, &m);
    ll max_ = 0, sum = 0, l = INF;
    for (int i = 1; i <= n; ++i) {
        scanf("%lld", &p[i]);
        max_ = max(max_, p[i]);
        sum += p[i];
        l = min(l, p[i]);
    }
    ll min_ = sum/n, r = max_;
    if (sum % n)
        min_ += 1;
    //cout << sum << "---" << n << endl;
    while (max_ >= min_) {
        ll mid = (max_ + min_) >> 1, sum_ = 0;
        for (int i = 1; i <= n; ++i)
            sum_ += max(0LL, p[i] - mid);
        if (sum_ <= m) {
            r = min(r, mid);
            max_ = mid - 1;
        }
        else
            min_ = mid + 1;
    }
    min_ = l; max_ = sum/n;
    while (max_ >= min_) {
        ll mid = (max_ + min_) >> 1, sum_ = 0;
        for (int i = 1; i <= n; ++i)
            sum_ += max(0LL, mid - p[i]);
        if (sum_ <= m) {
            min_ = mid + 1;
            l = max(l, mid);
        }
        else
            max_ = mid - 1;
    }
    //cout << r << "-----" << l << endl;
    printf("%lld\n", r - l);
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值