题解:P16236 [蓝桥杯 2026 省 B] LQ 聚合
文章来自我的洛谷题解:https://www.luogu.com.cn/article/npadgim4
题目传送门
题目分析
贪心好题。
容易得到对于每个位置 \(i\):
如果是 L:手里的 L 的数量 len++。
如果是 Q:此时每个之前的 L 都可以与当前 Q 形成聚合。
如果是 ?:先看看后面还有多少个 Q(记作 \(t = a_{i+1}\)),再看看攒了多少个 L(记作 \(s = len\))。
然后比一下 \(t\) 和 \(s\) 的大小:
如果 \(t > s\):把这个 ? 变成 L。如果 \(t \le s\):那就把它变成 Q。
证明难度不大
- 修复为
L的条件 \(t > s\) 意味着后续Q的数量更多,优先增加L能最大化未来配对数。 - 修复为
Q的条件 \(t \le s\) 意味着当前L的数量足够,立即形成聚合更优。
AC 代码
#include <bits/stdc++.h>
int a[100009]; // 存储每个位置之后 Q 的数量
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n; // 输入序列长度
string s;
cin >> s;
a[n] = 0; // 边界条件:末尾之后没有 Q
for (int i = n - 1; i >= 0; i--) {
a[i] = a[i + 1];
if (s[i] == 'Q') {
a[i]++;
}
}
ll ans = 0, len = 0, weizhi = 0; // ans:答案,len:当前 L 数量,weizhi:初始问号数量
for (char c : s) {
if (c == '?') {
weizhi++; // 统计问号总数
}
}
int yizhi = weizhi; // 剩余问号数量(用于遍历时更新)
for (int i = 0; i < n; i++) { // 遍历序列并决策
if (s[i] == 'L') {
len++; // 遇到 L,增加 L 数量
} else if (s[i] == 'Q') {
ans += len; // 遇到 Q,累加聚合数
} else if (s[i] == '?') { // 处理问号
ll t = a[i + 1] + (yizhi - 1), s = len; // t:后续 Q 数量,s:当前 L 数量
if (t > s) { // 条件满足时修复为 L
len++;
} else { // 否则修复为 Q
ans += len;
}
yizhi--; // 剩余问号数减一
}
}
cout << ans << endl; // 输出答案
return 0;
}

浙公网安备 33010602011771号