PAM学习笔记

感觉就是manacher和AC自动机的结合体

构造PAM

每个节点代表一个回文串,这个回文串是从根走到这个点在走上去
我们从如果从前面继承
我们设 \(fail[i]\) 为作为 \(i\) 后缀的最长回文串所在的状态,\(len[i]\) 为这个状态回文串的长度。
首先我们的结构是两颗 \(trie\),我们的 \(0\) 是偶根,也就是偶数长度回文串,\(1\) 是奇根。
初始化 \(fail[0]=1,len[1]=-1\)
这个还是在线构造的。
首先我们有个 \(get(x,i)\) 函数

int get(int x,int i){//代表从状态x的回文串的后缀回文串中找到一个左边和i相同的
    while(i-st[x].len-1<0||s[i-st[x].len-1]!=s[i]) x=st[x].link;
    return x;
}
void insert(int c,int i){
    lst=get(lst,i);
    if(!st[lst].nxt[c]){
        st[++cnt].link=st[get(st[lst].link,i)].nxt[c];//为了保证最小,也就是虽然我们现在可能不存在,但是我们之前可能出现过,所以利用它
        st[lst].nxt[c]=cnt;
        st[cnt].len=st[st[cnt].link].len+2;
        st[cnt].siz=st[st[cnt].link].siz+1;//以i结尾的数量
    }
    lst=st[lst].nxt[c];
}

例题

P5496

求两个相同的回文串数量。两个串建出 \(PAM\),然后相同的遍历即可
然后根据 \(link\) 往上即可。

P5555

差不多啊

双向PAM

高科技!我们发现我们往后添加字符和前面其实没有什么本质区别,无非是get那里我们变成了和后面的字符进行比较。但是这还有问题,如果我们新加之后等于了全串,那么要更新一下另一边?因为我们跳需要维护一个前面的link和后面的link,然后就做完了。

Loj6070

我们PAM也要有自己的好题!

考虑PAM求有多少个本质不同的回文串数,本质不同的回文串可以把回文串当作子串来处理。所以就是状态数了。我要写根号!因为在线询问,我们大力分块,我们维护tree[i][j]为第i到j块的字符串建出来的PAM是什么,然后我们使用双向PAM,询问的时候大力插入即可

这题一般吧,\(log^2\)不想学了

posted @ 2025-07-09 10:23  wuhupai  阅读(5)  评论(0)    收藏  举报