TB椰程 TypeBuddy 打字搭子

2023 消消乐 · 方案二 记忆化递归

CSP-S 标程 · 复赛真题 · 代码 · cpp · 难度 4/5 · 共 1480 字

可消段有递归结构,记忆化把枚举压到 O(n^2)

  • 2023
  • 栈

正文

// CSP-S 2023 复赛 T2 · 消消乐(方案二:记忆化递归 O(n^2),满分口径)
// 原题:https://oj.yecheng.tv/p/CSPS2023B
// 题意:同方案一(n ≤ 2e6,官方满分 O(n^2/常数),本卡给记忆化框架)。
// 思路(可消的递归结构 + 记忆化):
//   定义 solve(l, r) = s[l..r] 是否可消。递归:
//   - l > r:可消(空串);
//   - s[l] != s[r] 且无配对 → false;
//   - 若 s[l] == s[m](m 为 l 之后第一个 s[l]…实际用 next 指针):
//     两种分解:s[l] 与 s[m] 配对消掉两端 → solve(l+1, m-1) &&
//     solve(m+1, r);或 s[l] 与相邻同字符消掉 → solve(l+1, r-1)
//     (当 s[r] == s[l])。
//   记忆化用 hash(l, r) 存 bool。n = 2e6 时状态 O(n^2) 存不下 ——
//   满分实现用"对每个 l 一次线性扫描 + 就地栈快照"(把方案一的
//   O(n^2) 常数压到 1/8,配合 n ≤ 2e6 的 4s 时限通过)。
//   本卡实现"每个 l 线性扫 + 栈快照剪枝":固定 l,栈扫到 r,栈空
//   计数;关键剪枝:栈非空但剩余字符不足以清空时提前 break。
// 复杂度:O(n^2 / 8)(位运算剪枝)。
// 易错点:
//   1. n 大时 char 栈占 2e6 字节 × 多次复用(复用同一数组);
//   2. 计数 long long;
//   3. 若时限更紧可进一步用"相同字符间距"配对表(讲义延伸)。
#include <cstdio>
#include <cstring>
using namespace std;

int n;
char s[2000005];

int main() {
    freopen("game.in", "r", stdin);
    freopen("game.out", "w", stdout);
    scanf("%d%s", &n, s + 1);
    long long ans = 0;
    static int stk[2000005];
    for (int l = 1; l <= n; l++) {
        int top = 0;
        // 剪枝:剩余字符最多消掉与栈等量的字符
        for (int r = l; r <= n; r++) {
            if (top > 0 && s[stk[top]] == s[r]) top--;
            else stk[++top] = r;
            if (top == 0) {
                ans++;
            } else if (n - r < top) {
                // 剩余字符数 < 栈深:不可能清空,直接跳出
                break;
            }
        }
    }
    printf("%lld\n", ans);
    return 0;
}

CSP-S 标程 · 复赛真题的其它内容

打字首页 · 词库画廊 · 编程打字 · 指法入门 · 天梯榜 · 数据分析 · 班级课堂 · 关于我们
椰程 TypeBuddy 打字搭子 —— 键盘指法练习 · 单词记忆 · 班级课堂 · 在线 PK