1 条题解
-
0
C. 乌龟与好对 — 详细题解
题目重述
给定一个长度为 的字符串 ,可以任意重排。定义数对 ()是 好对 当且仅当:
- ,或者
- 是 令人愉快的对。
而 是令人愉快的对,当且仅当 存在 一个整数 ()使得:
- (相邻两个字符不同),且
- 或 。
目标:重排字符串,使好对的数量最大,输出任意最优重排结果。
一、理解“令人愉快的对”
先分析反面:什么样的 不是 令人愉快的对?
由定义,不是令人愉快的对,意味着:
对 所有 ,要么
(1) ,
要么
(2) 且 。这条件非常强。直观上说,如果 ,那么要让它不是好对, 这一段必须是非常“整齐”的:
要么相邻都相等,要么严格交替出现 和 。反之,只要区间内出现一次 相邻不同且不全等于两端,它就会成为令人愉快的对。
二、好对的构成
好对 = 相同字符对 + 令人愉快的不同字符对。
- 相同字符对:若字符 出现 次,则它贡献 个相同字符对。这部分在重排中固定,无法改变。
- 不同字符对:我们需要最大化其中 令人愉快的对 的数量。
所以问题简化为:重排字符串,使尽可能多的不同字符对 ()成为令人愉快的对。
三、核心观察
观察 1:如果字符串中没有两个相邻字符相同(即 对所有 ),那么对于任意 ,只要 ,取 ,则:
- 成立(因为没有相邻相同),
- 因为 ,所以 ? 等等注意:条件要求 或 。取 ,我们有 ,所以第一项 为假。那么需要第二项 为真。因为 且 ,不一定能推出 。所以不是自动成立。
因此需要更精细的分析。
观察 2(关键结论):通过构造和已知竞赛结论,最优策略是 将字符按出现次数从大到小排序,然后轮流从每种字符中取一个,形成新字符串。
等价说法:重复执行“按某种顺序(如字母顺序)遍历所有还有剩余的字符,各取一个加入答案”,直到所有字符用完。这种构造称为 循环放置 或 轮询放置。
四、为什么这种构造最优
直观解释:
- 尽可能打散相同字符:使相同字符不相邻(除非某字符数量超过一半,不可避免会相邻)。这最大化相邻不同的位置数。
- 最大化“变化点”:相邻不同越多,对于任意 ,区间内出现不同于 的字符的概率越大,从而更容易满足令人愉快的对条件。
- 可以证明:这种构造下,所有不同字符对 都成为好对,除非某种字符数量超过 的极端情况。即便如此,它也能达到理论最大值。
五、详细构造步骤(与标程一致)
- 统计 个字母的出现次数,存入数组 。
- 初始化答案字符串 为空。
- 重复以下步骤,直到所有 :
- 对于 到 :
- 如果 ,则将字符 加入 ,并将 减 。
- 对于 到 :
- 输出 。
时间复杂度:每轮循环遍历 个字母,总轮数为最大出现次数 ,故复杂度 ,即 。
六、正确性证明思路
- 相同字符对:数量固定,不受重排影响。
- 不同字符对:在循环放置的字符串中,对于任意 且 ,我们总能在 内找到一个相邻对 ,它们不同且至少有一个不等于 或 。
这是因为循环放置保证了字符分布均匀,除非整个区间只有 和 两种字符且严格交替,但若如此则 和 出现次数相差不超过 ,这种情况下 也可直接验证为好对。
严格证明较长,但竞赛结论已确认该构造最优。
七、示例验证
样例 :
- 计数:
- 构造:按字母顺序依次取 →
好对: 是令人愉快的对(取 , 且 )
可输出 等。
样例 :
- 计数:
- 构造轮询:
第 轮:
第 轮:
第 轮:(只剩 )
结果:
好对数量 ,与题目输出 同为最优。
样例 :
- 计数:
- 构造: 或 等,都最优。
八、结论
本题的解法出人意料地简单:循环放置所有字母。
不需要复杂的贪心证明,直接按上述步骤构造即可得到最优解。核心要点:
- 相同字符对数量固定。
- 循环放置最大化不同字符对成为好对的数量。
- 实现简单,复杂度 。
代码实现如下:
#include <bits/stdc++.h> using namespace std; void solve() { int n; string s; cin >> n >> s; vector<int> cnt(26, 0); for (char c : s) { cnt[c - 'a']++; } string ans; while (true) { bool has = false; for (int i = 0; i < 26; i++) { if (cnt[i] > 0) { ans += char('a' + i); cnt[i]--; has = true; } } if (!has) break; } cout << ans << "\n"; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
- 1
信息
- ID
- 7003
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者