/*
> 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;
}
CodeForces 883I
最新推荐文章于 2025-03-18 06:30:00 发布