一篇 PAM 的题解

· · 题解

前置知识

介绍详见 OI Wiki 中的描述,此处不作赘述。

思路分析

分两种情况讨论:

构建回文自动机,按照题意模拟即可。

删除操作

由于 PAM 结点只增不减(保证 fail 指针有效及结点复用),删除时采用状态回滚策略,通过维护历史栈恢复上一状态。

复杂度分析

代码实现

#include <bits/stdc++.h>
using namespace std;
#define int long long // 十年OI一场空,不开long long见祖宗
const int N = 10010;
const int AL = 26;
struct PAM {
    int n, last, tot;
    int tp; // 回文子串总数量
    int len[N], fail[N];
    int num[N]; // 以该节点结尾的回文后缀个数
    int nextt[N][AL];
    vector<int> lh; // last历史栈,回滚用
    vector<int> th; // tp历史栈,回滚用
    vector<int> ch;
    int s[N];
    PAM() {
        init();
    }
    void init() {
        n = 0; last = 0; tot = 2; tp = 0;
        len[0] = 0; fail[0] = 1;
        len[1] = -1; fail[1] = 1;
        num[0] = num[1] = 0;
        s[0] = -1; // 哨兵,防止get_fail越界
        memset(nextt, 0, sizeof(nextt));
        lh.clear(); th.clear(); ch.clear();
        lh.push_back(last);
        th.push_back(tp);
    }
    int get_fail(int x) {
        while (s[n - len[x] - 1] != s[n]) {
            x = fail[x];
        }
        return x;
    }
    void add(int c) {
        s[++n] = c;
        int cur = get_fail(last);
        if (!nextt[cur][c]) {
            int now = tot++;
            len[now] = len[cur] + 2;
            fail[now] = (len[now] == 1) ? 0 : nextt[get_fail(fail[cur])][c];
            nextt[cur][c] = now;
            num[now] = num[fail[now]] + 1;
        }
        last = nextt[cur][c];
        tp += num[last];
        ch.push_back(c);
        lh.push_back(last);
        th.push_back(tp);
    }
    void remove() {
        if (n == 0) {
            return;
        }
        ch.pop_back();
        lh.pop_back();
        th.pop_back();
        last = lh.back();
        tp = th.back();
        n--;
    }
    int get_total() {
        return tp;
    }
};
PAM p;
signed main() { // 注意此处main函数类型不能用int
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int q;
    cin >> q;
    while (q--) {
        char op;
        cin >> op;
        if (op != '-') {
            p.add(op - 'a');
        }
        else {
            p.remove();
        }
        cout << p.get_total() << ' ';
    }
    return 0;
}