题解: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;
}
posted @ 2026-04-26 18:41  Lexot  阅读(45)  评论(0)    收藏  举报