二分算法题目训练(四)——Robin Hood详解

本文深入探讨了基于二分法的RobinHood算法,通过分析Kekoland中公民财富分配问题,介绍了如何在限定时间内调整贫富差距。文章详细解释了算法流程,包括寻找平均值、分类人群以及通过二分法确定最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二分算法题目训练(四)——Robin Hood详解

codeforces672D——Robin Hood详解

  • Robin Hood
  • 问题描述(google翻译)

    • 我们都知道罗宾汉令人印象深刻的故事。罗宾汉利用他的射箭技巧和他的智慧从富人那里偷钱,然后把它归还给穷人。

      在Kekoland有n个公民,每个人都有ci硬币。每天,罗宾汉将从该市最富有的人那里拿出1枚硬币,然后将它交给最贫穷的人(最富有的1枚硬币后最穷的人)。如果选择不是唯一的,他将随机选择其中一个。可悲的是,罗宾汉已经老了,想要在k天退休。他决定在最后几天帮助穷人。

      罗宾汉拿走他的钱后,最富有的人也可能成为最穷的人,甚至可能会发生罗宾汉将他的钱还给他的钱。例如,如果所有人拥有相同数量的硬币,那么第二天他们也将拥有相同数量的硬币。

      你的任务是找出k天后最富有和最贫穷的人之间的差异。请注意,最富有和最穷的人随意选择不会影响答案。

  • 输入

    • 输入的第一行包含两个整数n和k(1≤n≤500000,0≤k≤109) - Kekoland的公民人数和Robin Hood退休前剩余的天数。

      第二行包含n个整数,其中第i个是ci(1≤ci≤109) - 第i个人的初始财富。

  • 输出
    • 打印一行,包含最富裕和最贫穷人口财富之间的差异。
  • 样例输入 1
    • 4 1
      1 1 4 2
  • 样例输出 1
    • 2
  • 样例输入 2
    • 3 1
      2 2 2
  • 样例输出 2
    • 0
  • 问题分析
    • 算出这批数据的平均值,将人群分为高于平均水平和低于平均水平的两类
    • 二分法找到一个均值,满足低于平均水平并且在 k 天内能补回平均水平的人,k 为控制变量
    • 二分法找到一个均值,满足高于平均水平并且在 k 天内能捐出去的人的集合,k 为控制变量
    • 两个均值差就是贫富差
#include <iostream>

#define Maxn 5000001

using namespace std;

typedef long long int LL;

LL n;    //people
int k;  //days
int money;
LL people[Maxn] = {0};

int judge(LL day);
int judge1(LL day);

int main()
{
    ios::sync_with_stdio(false);
    LL i = 1;
    LL sum = 0;
    cin >> n >> k;
    for(; i <= n; i++)
    {
        cin>>people[i];
        sum += people[i];
    }
    LL limit = sum / n;
    LL limit2 = limit;
    if(sum % n)
        limit2++;
    LL l = 1;
    LL r = limit;
    LL mid;
    LL result = 0,mark = 0,mark1 = 0;
    while(l <= r)
    {
        mid= (l + r) / 2;
        if(judge(mid))
        {
            mark = mid;
            l = mid + 1;
        }
        else
        {
            r = mid - 1;
        }
    }
    l = limit2;
    r = sum;
    while(l <= r)
    {
        mid = (l + r) / 2;
        if(judge1(mid))
        {
            mark1 = mid;
            r = mid - 1;
        }
        else
        {
            l = mid + 1;
        }
    }
    result = mark1 - mark;
    cout<<result;
    return 0;
}

int judge(LL day)
{
    LL res = 0;
    for(LL j = 1;j <= n;j++)
    {
        if(people[j] < day)
            res += day - people[j];
    }
    return res <= k;
}
int judge1(LL day)
{
    LL res = 0;
    for(LL j = 1;j <= n;j++)
    {
        if(people[j] > day)
            res += people[j] - day;
    }
    return res <= k;
}

 

 
posted @ 2018-08-08 19:17 Nikki_o3o 阅读( ...) 评论( ...) 编辑 收藏
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值