CodeForces 883I

/*
> Problem:CodeForces 883I
> Author: WESTWOOD
> Mail: 965194745@qq.com
> Created Time: 2017/10/23 21:35:32
> function:题目描述的是给定最小分组的大小k,求解一种合法的分发使得分组花费最大值最小。
           每个组分组花费是组内最大值减去最小值
           想到的方法是先对每个值排个序,然后二分花费,判断分组可行性
           判断分组可行性的方法
           不能贪心的吸收组员,那样会导致某几个组太大,某几个组小过最小分组。要均匀的分
           考虑每个分组情况,如果从第一个人开始,那么包括他的前k个人都是必须在一起的,然后
           后面满足花费的组员是自由的,可以加入这个组,或者自己开一组。然后把这些自由人标记起来
           自由人才有权力去开新组产生更多的自由人。最后判断最后一个人是不是自由人
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<set>
#pragma warning(disable : 4996)
using namespace std;
const int MAXN = 3E5 + 10;
int bit[MAXN];
int n, k;
inline int lower_bit(int i)
{
    return i&-i;
}
void add(int i, int a)
{
    while (i<=n)
    {
        bit[i] += a;
        i += lower_bit(i);
    }
}
int sum(int i)
{
    int a = 0;
    while (i)
    {
        a += bit[i];
        i -= lower_bit(i);
    }
    return a;
}
void fill(int l, int r)//标记l~r的人为自由人
{
    if (l > r) return;
    add(l, 1);
    add(r + 1, -1);
}
int a[MAXN];

bool check(int m)
{
    memset(bit, 0, sizeof bit);
    set<int> p;//用于保存需要新开组队的人
    p.insert(1);
    for (int i = 1;i <= n;i++)
    {
        if (sum(i)||p.count(i))
        {
            p.erase(i);
            int l = i + k, r = upper_bound(a + i, a + 1 + n, a[i] + m) - a - 1;//覆盖范围
            fill(l, r);
            if(r-i+1>=k)p.insert(r + 1);//如果能合法组队
            if (i == n-k+1 && r == n) return true;//如果是这种情况下就是说第n个人刚好可以被组,而不会变成自由人
        }
    }
    return sum(n);
}
int main()
{
    if (fopen("in.txt", "r") != NULL)
    {
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    }
    cin >> n >> k;
    for (int i = 1;i <= n;i++)
        cin >> a[i];
    sort(a+1, a+1+n);
    int l = 0, r = 1e9;
    for (int i = 0;i<35;i++)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid;
    }
    cout << r;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值