Manacher Algorithm
Find the longest substring which is palindrome.
在搜索到i 时,
- cc,ll,rr已经找到的右边界最大的回文串的中心、左端和右端。
- p[i]以i 为中心的最长回文串长度。如果i 在最长回文串之中,- p[i]至少是它对称位置的- p[mirror]。利用此性质快速计算- p[i]。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | vector<int> manacher(const string& s) {string t = "#";
 for (auto c : s) t += c, t += '#';
 const int n = t.size();
 vector<int> r(n);
 for (int i = 0, j = 0; i < n; i++) {
 if (2 * j - i >= 0 && j + r[j] > i) {
 r[i] = min(r[2 * j - i], j + r[j] - i);
 }
 while (i - r[i] >= 0 && i + r[i] < n && t[i - r[i]] == t[i + r[i]]) {
 r[i]++;
 }
 if (i + r[i] > j + r[j]) {
 j = i;
 }
 }
 return r;
 }
 
 | 
如果 rad[l + r] > r - l,表明子串[l,r) 是回文串。
定义一个字符串是k-good 的,当且仅当该字符串 存在 长为k 的 非 回文子串。对于字符串t,定义f(t) 为满足t 是k-good 的正整数k 的总和。对于给定的一个长为n 的字符串s,你需要回答q 个询问,每次询问给出l,r,求f(slsl+1…sr) 的值。
数据范围:1⩽n,q⩽2⋅105。
存在转任意,考虑一个字符串是k-bad 的,则所有长为k 的子串都是回文的。这个条件很苛刻,考虑到
s0=sk−1=s2=sk+1=⋯
如果k 为偶数,字符串是k-bad 的当且仅当它每个字符都相同,如果是奇数,要么每个字符都相同,要么是ababa 的形式。
特判k=∣s∣,此时上述式子只有s0=sk−1 成立,不能推出任何结论,因此只能s 本身是回文的。
| 12
 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
 
 | int n, q;cin >> n >> q;
 
 string s;
 cin >> s;
 
 vector<int> lst1(n), lst2(n);
 for (int i = n - 1; i >= 0; i--) {
 lst1[i] = i + 1 < n && s[i] == s[i + 1] ? lst1[i + 1] : i + 1;
 lst2[i] = i + 2 < n && s[i] == s[i + 2] ? lst2[i + 2] : i + 2;
 }
 
 auto rad = manacher(s);
 auto cal = [&](int l, int r, int d) {
 assert((r - l) % d == 0);
 return 1ll * (l + r) * ((r - l) / d + 1) / 2;
 };
 
 while (q--) {
 int l, r;
 cin >> l >> r;
 l--;
 int len = r - l;
 
 ll ans = cal(2, len, 1);
 if (lst1[l] >= r) {
 ans -= cal(2, (len - 1) - (len - 1) % 2, 2);
 }
 if (lst2[l] >= r && lst2[l + 1] >= r) {
 ans -= cal(3, (len - 1) - len % 2, 2);
 }
 if (rad[l + r] > len) {
 ans -= len;
 }
 cout << ans << "\n";
 }
 
 | 
 回文自动机
| 12
 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
 
 | struct PAM {static constexpr int ALPHABET_SIZE = 28;
 struct Node {
 int len;
 int link;
 int cnt;
 array<int, ALPHABET_SIZE> next;
 Node() : len{}, link{}, cnt{}, next{} {}
 };
 vector<Node> t;
 int suff;
 string s;
 PAM() {
 init();
 }
 void init() {
 t.assign(2, Node());
 t[0].len = -1;
 suff = 1;
 s.clear();
 }
 int newNode() {
 t.emplace_back();
 return t.size() - 1;
 }
 
 bool add(char c, char offset = 'a') {
 int pos = s.size();
 s += c;
 int let = c - offset;
 int cur = suff, curlen = 0;
 
 while (true) {
 curlen = t[cur].len;
 if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos])
 break;
 cur = t[cur].link;
 }
 if (t[cur].next[let]) {
 suff = t[cur].next[let];
 return false;
 }
 
 int num = newNode();
 suff = num;
 t[num].len = t[cur].len + 2;
 t[cur].next[let] = num;
 
 if (t[num].len == 1) {
 t[num].link = 1;
 t[num].cnt = 1;
 return true;
 }
 
 while (true) {
 cur = t[cur].link;
 curlen = t[cur].len;
 if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos]) {
 t[num].link = t[cur].next[let];
 break;
 }
 }
 
 t[num].cnt = 1 + t[t[num].link].cnt;
 
 return true;
 }
 };
 
 |