小红的纸牌游戏
[题目链接](https://www.nowcoder.com/practice/a454e716209c467c924577295f6e0d8d)
思路
本题是一个博弈 + 贪心问题。 张纸牌排成一行,每张上面写着
或
。小红和小紫轮流取走一张牌(小红先手),直到剩下
张牌,剩余牌按原始顺序拼成一个二进制数。小红想让这个数尽可能大,小紫想让它尽可能小。
贪心策略
二进制数的高位比低位重要得多,因此双方都应该优先影响高位。对于每一方:
- 小红(最大化):希望高位是
,因此她应该移除最左边的
。去掉一个靠前的
,相当于让后面的
顶上更高位。如果没有
可移除(全是
),那移除哪张都一样,选择移除最右边的
以保留尽可能多的高位。
- 小紫(最小化):希望高位是
,因此她应该移除最左边的
。去掉一个靠前的
,相当于让后面的
顶上更高位。如果没有
可移除(全是
),选择移除最右边的
。
举例
以样例 10110,,
为例,共需移除
张牌:
| 轮次 | 玩家 | 操作 | 剩余牌 |
|---|---|---|---|
| 初始 | — | — | 10110 |
| 1 | 小红 | 移除最左边的 0(第 2 张) | 1110 |
| 2 | 小紫 | 移除最左边的 1(第 1 张) | 110 |
最终结果为 110。
正确性
这个贪心策略之所以正确,是因为在二进制表示中,高位的权重远大于所有低位权重之和()。因此无论后续局面如何变化,优先操作最左边(最高位方向)的目标字符,都能带来最大收益。
代码
直接模拟博弈过程。用链表维护当前牌序列,每轮按贪心策略移除对应字符。
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, k;
scanf("%d%d", &n, &k);
char s[200005];
scanf("%s", s);
list<char> cards(s, s + n);
int removals = n - k;
for (int turn = 0; turn < removals; turn++) {
if (turn % 2 == 0) {
// 小红:移除最左边的 '0',若无则移除最右边的 '1'
auto it = find(cards.begin(), cards.end(), '0');
if (it != cards.end()) {
cards.erase(it);
} else {
auto rit = cards.end();
--rit;
cards.erase(rit);
}
} else {
// 小紫:移除最左边的 '1',若无则移除最右边的 '0'
auto it = find(cards.begin(), cards.end(), '1');
if (it != cards.end()) {
cards.erase(it);
} else {
auto rit = cards.end();
--rit;
cards.erase(rit);
}
}
}
for (char c : cards) putchar(c);
putchar('\n');
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), k = sc.nextInt();
String s = sc.next();
LinkedList<Character> cards = new LinkedList<>();
for (char c : s.toCharArray()) cards.add(c);
int removals = n - k;
for (int turn = 0; turn < removals; turn++) {
if (turn % 2 == 0) {
// 小红:移除最左边的 '0',若无则移除最右边的 '1'
int idx = cards.indexOf('0');
if (idx != -1) {
cards.remove(idx);
} else {
cards.removeLast();
}
} else {
// 小紫:移除最左边的 '1',若无则移除最右边的 '0'
int idx = cards.indexOf('1');
if (idx != -1) {
cards.remove(idx);
} else {
cards.removeLast();
}
}
}
StringBuilder sb = new StringBuilder();
for (char c : cards) sb.append(c);
System.out.println(sb.toString());
}
}
复杂度分析
- 时间复杂度:
,共
轮,每轮在链表中查找目标字符需要
。对于本题
的数据范围,可以通过。
- 空间复杂度:
,链表存储所有牌。

京公网安备 11010502036488号