通过分析游戏无限进行的稳态条件,转化为降序排序后寻找最大满足 a[i] >= i 的人数。
OJ: roj
题目 ID: 10005
难度:普及+/提高-
标签:贪心排序思维
创建: 2026-10-09 23:32
更新: 2026-10-09 23:32
形式化题目
有
- 自己不出局。
- 在保证自己不出局的前提下,希望出局的人数尽可能多。 求在所有人都采取最优策略下,最终游戏最少剩下的存活人数。
正解
思路
本题需要考虑玩家在游戏无限进行时的存活条件。
假设当前有
- 绝对安全条件:如果某个玩家的
,那么他每轮能够拿到 张牌。即使他在这一轮中被剩下的所有人“集火”针对,他最多也就是失去 张牌。由于他的收支永远保证 ,而初始有 张牌( 足够多,且在一轮内最多失去 张牌,不会导致首轮暴毙),所以该玩家的牌数永远不会减少,也就绝对不可能出局。 - 必然出局条件:如果某个玩家的
,那么他单轮最多只能获取 张牌。如果其他玩家为了“让尽可能多的人出局”而联合起来集火他,他每轮会失去 张牌。这样他每轮净亏损至少 张牌。在无限进行的游戏中,该玩家的牌数迟早会扣到 0,从而被淘汰。
综上所述,当剩余
由于能够存活的人必定是
代码
#!/usr/bin/env python3
# Author: 2026-10-09 22:30
import sys
def solve() -> None:
input_data = sys.stdin.read().split()
if not input_data:
return
n = int(input_data[0])
a = []
for i in range(1, n + 1):
a.append(int(input_data[i]))
a.sort(reverse=True)
ans = 0
for i in range(n):
if a[i] >= i:
ans = i + 1
else:
break
print(ans)
if __name__ == '__main__':
solve()/*
* Author: 2026-10-09 22:30
*/
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 100005;
ll a[MAXN];
int n;
bool cmp(ll x, ll y) {
return x > y;
}
void solve() {
if (!(cin >> n)) return;
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
sort(a, a + n, cmp);
int ans = 0;
for (int i = 0; i < n; ++i) {
if (a[i] >= i) {
ans = i + 1;
} else {
break;
}
}
cout << ans << "\n";
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
solve();
return 0;
}复杂度
- 时间复杂度:排序的时间复杂度为
,随后只需遍历一次数组,时间复杂度为 。总体时间复杂度为 ,可以轻松通过 1000ms 的时限。 - 空间复杂度:保存所有人参数的数组空间为
,空间消耗远低于 128MB 的内存限制。
总结
这道题的绝妙之处在于“无限轮”下的收益平衡,并且题目给出了一个精妙的条件——初始每人有
1. 算法与完整推导、复杂度:
核心算法为:将
2. 数据范围:
- 时限:1000ms
- 内存:128MB
3. 输出格式: 一个整数,直接输出最终剩下的最少人数。最后带有换行,无任何多余空格。
4. T9 五项排查:
- 多组数据:无。
- 边界情况:
时直接输出 1; 的极端情况均可处理。 - 顺序与初始值:题目特意规定初始每人有
张牌,这保证了在第一轮中(即使大家轮流拿牌),每人最多被拿走 张牌,不会出现刚开局还未出手就被淘汰的“冤死”情况。这就将复杂的先后手博弈转化为了纯粹的轮均收益比较! - 数据类型:
,使用 long long避免溢出。 - 格式:无行末空格。
5. 逐点数据表:
| 数据点 | 输入特征 | 输出 | 结果说明 |
|---|---|---|---|
2.in |
2 个人,1 1 |
2 |
初始各自有一牌的拿牌能力,都不会出局。 |
4.in |
3 个人,2 5 2 |
3 |
5 2 2,全部 |
5.in |
50012 |
大数据,有效验证 |
6. 声明:
本题有官方数据,验证基准是与 .out 逐字节比对。
验证记录(R2 补充)
本题有官方数据 ⇒ 证据等级 ★★★★★(与官方
.out逐字节比对)。
结论:真实数据 10/10 逐字节通过
★ 算法裁定:「官方数据站在 greedy(贪心)一边」
本题存在两个候选算法:greedy(贪心)与 M3(另一候选)。
验证方式是在全部 10 个数据点上逐点对比两者的输出:
| 项 | 结论 |
|---|---|
| 数据立场 | 官方数据选了 greedy |
| 判据 | greedy vs M3 的 10 点逐点对比 |
★ 结论分层的必要声明(T14):
这是数据驱动的裁定,不是数学证明。
⇒ 报告中必须写「官方数据选择了 greedy」,
而不能写「greedy 是唯一正确答案」。
证据 | 声明
✅ 真实数据 10/10 逐字节(★★★★★)
✅ greedy 与 M3 在 10 个点上对比 ⇒ 数据选 greedy
⚠ 「greedy 正确」是数据裁定,不是普适证明(诚实边界)