PAM 入门
前后端插入
题目链接:https://vjudge.net/problem/HDU-5421
注意到回文后缀也是回文前缀,所以大体上没有变化。
只是要维护最长回文前缀和后缀,当最长回文前/后缀等于原串时,记得更新另外一个。
时间复杂度:$O(n)$ 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| #include<cstdio> #include<cstring> #include<iostream> #include<string> using namespace std; typedef long long LL; const int N = 1e5 + 5; int len[N], fail[N], go[N][26], llast, rlast, pam_cnt; int dep[N]; LL ans;
char s[N * 2]; int lenl, lenr, n; void clgo(int x){memset(go[x], 0, sizeof(go[x]));} void init(){ fail[0] = pam_cnt = 1; len[1] = -1; llast = rlast = 0; ans = 0; clgo(0); clgo(1); } int getLfail(int p){ while(lenl + len[p] + 1 > lenr || s[lenl + len[p] + 1] != s[lenl]) p = fail[p]; return p; } int getRfail(int p){ while(lenr - len[p] - 1 < lenl || s[lenr - len[p] - 1] != s[lenr]) p = fail[p]; return p; } void extend(int type){ int p, c, *last; if(type == 0) p = getLfail(llast), c = s[lenl] - 'a', last = &llast; else p = getRfail(rlast), c = s[lenr] - 'a', last = &rlast; if(!go[p][c]){ int q = ++pam_cnt, now = p; clgo(q); len[q] = len[p] + 2; if(type == 0) p = getLfail(fail[p]); else p = getRfail(fail[p]); fail[q] = go[p][c]; go[now][c] = q; dep[q] = dep[fail[q]] + 1; if(lenr - lenl + 1 == len[q]) llast = rlast = q; else *last = q; } else *last = go[p][c]; ans += dep[*last]; }
int main(){ while(cin >> n){ init(); lenl = n + 1; lenr = n; for(int i = 1; i <= n; i++){ int type; cin >> type; if(type <= 2){ string x; cin >> x; if(type == 1) s[--lenl] = x[0], extend(0); else s[++lenr] = x[0], extend(1); } else if(type == 3) cout << pam_cnt - 1 << "\n"; else cout << ans << "\n"; } } return 0; }
|
今天突然意识到一个很严重的问题,双端插入回文串的时间复杂度为啥对呢?原因是最长回文前后缀相等的那个特判,如果不加分析,会破坏均摊分析,所以现在来分析一下双端插入回文串的时间复杂度:
不妨认为插入到后面,插入后左边的最长回文前缀为 $L$ ,右边为 $R$ ,显然 $L$ 是 $R$ 的最长回文真前缀,否则与插入前 $L$ 是最长回文前缀矛盾,所以在回文树上,$L$ 和 $R$ 的深度差恰好为 $1$ ,所以这个操作只会让势能增加 $1$ ,不会破坏均摊分析。
证毕。
去均摊化
可以用于解决后端插入/删除 、 Trie 上 PAM 、可持久化 PAM 的问题。
详情请见 KMP 和 PAM 的可持久化。
在此不再赘述。
前后端插入/删除
PS :同样可以用同样的方法可持久化。