VMC 组队
组队

问最少的队伍的人数最大值,典型的二分,唯一的难点在于如何 check 答案。
由于不能确定一个队几个人更优,所以先保证能组成人数最少的队伍(即一个队 mid 个人),并记录以能力值 \(a_i\) 结尾的队伍数量,用于判断“散户”能否成功入队。
数据处理上需要对原 \(a_i\) 数组进行离散化,开一个权值的桶用于记录每个离散化后的能力值有多少人,方便能力值相同者的处理。check 时按能力值对桶进行扫描,使组队必须以当前枚举的 \(i\) 为队伍的首个成员。
由于要求 \(i\) 到 \(i+mid-1\) 的区间最小值,因此需要一棵支持区间减法,区间查询最小值的线段树。
代码如下:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read();
const int N = 3e5 + 5;
int n, a[N], b[N], Finish[N];
namespace Segment_Tree {
const int M = N << 2;
#define ls x << 1
#define rs x << 1 | 1
int a[M], n, lz[M];
void push_up(int x) {
a[x] = min(a[ls], a[rs]);
}
void push_down(int x) {
if (!lz[x]) return;
lz[ls] += lz[x], lz[rs] += lz[x];
a[ls] -= lz[x], a[rs] -= lz[x];
lz[x] = 0;
}
void build(int x = 1, int l = 1, int r = n) {
lz[x] = 0;
if (l == r) {
a[x] = b[l];
return;
}
int mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
push_up(x);
}
int query_Min(int x, int ql, int qr, int l = 1, int r = n) {
if (ql <= l and r <= qr) {
return a[x];
}
push_down(x);
int mid = l + r >> 1, ans = 1e9;
if (ql <= mid) ans = min(ans, query_Min(ls, ql, qr, l, mid));
if (qr > mid) ans = min(ans, query_Min(rs, ql, qr, mid + 1, r));
return ans;
}
void upd(int x, int ql, int qr, int minus, int l = 1, int r = n) {
if (ql <= l and r <= qr) {
lz[x] += minus;
a[x] -= minus;
return;
}
push_down(x);
int mid = l + r >> 1;
if (ql <= mid) upd(ls, ql, qr, minus, l, mid);
if (qr > mid) upd(rs, ql, qr, minus, mid + 1, r);
push_up(x);
}
} // namespace Segment_Tree
bool check(int mid, int Mx) {
Segment_Tree::build();
for (int i = 1; i <= Mx; ++i) Finish[i] = 0;
for (int i = 1; i <= Mx; ++i) {
if (i + mid - 1 <= Mx) {
int Mi = Segment_Tree::query_Min(1, i, i + mid - 1);
Segment_Tree::upd(1, i, i + mid - 1, Mi);
Finish[i + mid - 1] += Mi;
}
int newA = Segment_Tree::query_Min(1, i, i);
if (newA > Finish[i - 1])
return false;
Finish[i] += newA;
}
return true;
}
int main() {
n = read();
for (int i = 1; i <= n; ++i) {
a[i] = read();
}
sort(a + 1, a + n + 1);
int cnt = 1;
b[1] = 1;
for (int i = 2; i <= n; ++i) {
if (a[i] - a[i - 1] > 1) cnt += 2;
if (a[i] - a[i - 1] == 1) cnt++;
++b[cnt];
}
Segment_Tree::n = cnt;
int l = 1, r = n, ans = 0;
while (l <= r) {
int mid = l + r >> 1;
check(mid, cnt) ? l = mid + 1, ans = mid : r = mid - 1;
}
printf("%d\n", ans);
return 0;
}
inline int read() {
int x = 0;
char c = getchar();
bool f = 1;
while (!isdigit(c))
f = c ^ 45, c = getchar();
while (isdigit(c))
x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
return f ? x : -x;
}
本文来自博客园,作者:Maplisky,转载请注明原文链接:https://www.cnblogs.com/lbh2021/p/18722594

浙公网安备 33010602011771号