模板 - 回文自动机

构造一种fail向同一个节点的回文机:
abadabacaba
这样caba和daba都会指向ba。

带展示功能的回文自动机:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

struct Node {
    int len, ch[26], fail;
    int cnt;
    string str;
    Node(int len = 0) : len(len), fail(0) {
        memset(ch, 0, sizeof(ch));
        //下面是维护额外信息
        cnt = 0;
        str="";
    }
    void show() {
        printf("  str=\"%s\"\n", str.c_str());
        printf("  len=%d cnt=%d\n",len,cnt);
    }
};

const int MAXN = 600000;

//PalindromicAutomaton
struct PAM {
    Node nd[MAXN + 5];

    int len, top, last;     // len为字符串长度,top为节点个数,last为最后插入字符所对应的节点
    char s[MAXN + 5];
    string ls;  //用来展示的辅助字符串

    int getfail(int x) {        //沿着fail指针找到第一个回文后缀
        while(s[len - nd[x].len - 1] != s[len])
            x = nd[x].fail;
        return x;
    }

    void init() {
        len = 0, top = 0, last = 0;
        nd[top] = Node(0);
        nd[top].fail = 1;
        nd[++top] = Node(-1);
        nd[top].fail = 0;
        s[0] = '$';
    }

    void extend(char c) {
        s[++len] = c;
        int now = getfail(last);     //找到插入的位置
        ls = nd[now].str + c;   //用来展示的辅助字符串
        if(!nd[now].ch[c - 'a']) {     //若没有这个节点,则新建并求出它的fail指针
            nd[++top] = Node(nd[now].len + 2);
            nd[top].fail = nd[getfail(nd[now].fail)].ch[c - 'a'];
            nd[now].ch[c - 'a'] = top;
        }
        last = nd[now].ch[c - 'a'];
        nd[last].str = ls;  //用来展示的辅助字符串
        //下面是维护额外信息
        ++nd[last].cnt;
    }

    void show() {
        for(int i = top; i >= 0; --i) {
            printf("node:  id=%d\n", i);
            nd[i].show();
            printf("fail:  id=%d\n", nd[i].fail);
            nd[nd[i].fail].show();
            puts("");
        }
    }
} pam;

char s[MAXN + 5];
ll ans[MAXN + 5];

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    while(~scanf("%s", s)) {
        int n = strlen(s);
        pam.init();
        for(int i = 0; s[i] != '\0'; ++i)
            pam.extend(s[i]);
        //pam.show();
        for(int i = pam.top; i >= 2; --i) {
            Node *now = &pam.nd[i];
            Node *fail = &pam.nd[now->fail];
            fail->cnt += now->cnt;
        }
        pam.show();
    }
    return 0;
}
posted @ 2019-07-25 21:25  韵意  阅读(152)  评论(0编辑  收藏  举报