视频加载失败

安吉D9-T2

1101 字
6 分钟
安吉D9-T2
原题呈现

P4447 分组#

题目描述#

小可可的学校信息组总共有 nn 个队员,每个人都有一个实力值 aia_i.现在,一年一度的编程大赛就要到了,小可可的学校获得了若干个参赛名额,教练决定把学校信息组的 nn 个队员分成若干个小组去参加这场比赛.

但是每个队员都不会愿意与实力跟自己过于悬殊的队员组队,于是要求分成的每个小组的队员实力值连续,同时,一个队不需要两个实力相同的选手.举个例子:[1,2,3,4,5][1, 2, 3, 4, 5] 是合法的分组方案,因为实力值连续;[1,2,3,5][1, 2, 3, 5] 不是合法的分组方案,因为实力值不连续;[0,1,1,2][0, 1, 1, 2] 同样不是合法的分组方案,因为出现了两个实力值为 11 的选手.

如果有小组内人数太少,就会因为时间不够而无法获得高分,于是小可可想让你给出一个合法的分组方案,满足所有人都恰好分到一个小组,使得人数最少的组人数最多,输出人数最少的组人数的最大值.

注意:实力值可能是负数,分组的数量没有限制.

输入格式#

输入有两行:

第一行一个正整数 nn,表示队员数量.

第二行有 nn 个整数,第 ii 个整数 aia_i 表示第 ii 个队员的实力.

输出格式#

输出一行,包括一个正整数,表示人数最少的组的人数最大值.

输入输出样例 #1#

输入 #1#

7
4 5 2 3 -4 -3 -5

输出 #1#

3

说明/提示#

样例解释#

分为 22 组,一组的队员实力值是 [4,5,2,3][4, 5, 2, 3],一组是 [4,3,5][-4, -3, -5],其中最小的组人数为 33,可以发现没有比 33 更优的分法了.

数据范围#

对于 100%100\% 的数据满足:1n1051\leq n\leq 10^5ai109|a_i|\leq10^9

本题共 1010 个测试点,编号为 1101\sim10,每个测试点额外保证如下:

测试点编号数据限制
121\sim2n6,1ai100n\leq 6, 1\leq a_i \leq 100
343\sim4n1000,1ai105n\leq 1000, 1\leq a_i\leq 10^5aia_i 互不相同
565\sim6n105n\leq 10^5aia_i 互不相同
787\sim8n105,1ai105n\leq 10^5, 1\leq a_i \leq10^5
9109\sim 10n105,109ai109n\leq 10^5, -10^9 \leq a_i \leq 10^9

此题使用贪心.

考虑下面这个情景:有一些人已经分好了组,每一组可以看作一条链,每一条链都单调递增,且公差为 1.现在,来了一个实力值正好同时可以接在这几条链末尾的人.此时,不难发现贪心策略:将这个人放在最短的链末尾.

依照这个策略,我们可以建立一个优先队列,用于存储以当前值减一为末尾的链的长度.在读取输入时,记录每个权值和对应的人数,接下来,从小到大遍历每一个权值 ii

  • 对于每一个权值为 ii 的人:可以接在当前处于优先队列中的最短的链上.更新长度,并将长度移动到第二个优先队列(该队列用于保存已经吸纳了当前权值的人的小组,即以当前值为末尾的链).
  • 在遍历完该权值的所有人之后,如果有一组没有收集到该权值的任意一个人(即还留在第一个优先队列),那么该链断裂,不能再吸纳更多的人.将其与答案取最小值,并删除这一条链.
  • 将所有存于第二个优先队列的链移动到第一个.

标程

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 100;
int n, a[N], ans = 1e9 + 10;
priority_queue<int> us[2];
struct Node {
int v, num;
friend bool operator<(const Node a, const Node b) { return a.v < b.v; }
} d[N];
void clear(int idx) {
while (!us[idx].empty()) {
ans = min(ans, -us[idx].top());
us[idx].pop();
}
}
signed main() {
cin >> n;
int cnt = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
sort(a + 1, a + n + 1);
for (int i = 1; i <= n; i++) {
if (a[i] == a[i - 1]) {
d[cnt].num++;
} else {
d[++cnt].v = a[i];
d[cnt].num = 1;
}
}
for (int i = 1; i <= cnt; i++) {
int now = i & 1, pre = (i - 1) & 1;
if (d[i].v != d[i - 1].v + 1) {
clear(pre);
}
for (int j = 1; j <= d[i].num; j++) {
if (us[pre].empty()) {
us[now].push(-1);
} else {
int top = us[pre].top();
us[pre].pop();
us[now].push(top - 1);
}
}
clear(pre);
}
clear(0);
clear(1);
cout << ans;
return 0;
}

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

安吉D9-T2
https://blog.jerrylab.top/posts/problem/anji2026/D9/T2/
作者
Jerry
发布于
2026-08-09
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
Jerry
Hello, I'm Jerry.
公告
欢迎来到我的博客!这是一则示例公告。
分类
标签
最新动态
站点统计
文章
80
分类
3
标签
35
总字数
89,198
运行时长
0
最后活动
0 天前
站点信息
构建平台
Cloudflare Pages
博客版本
Firefly v6.16.5
文章许可
CC BY-NC-SA 4.0