【Title link】
【Key points of thinking】
- Insert # between every two characters (for example: " AAB "\(\Rightarrow\)" #A#A#B# ").
- Use the Manacher algorithm to find the length of the longest palindrome substring \(l_i\) centered on each character of the above string.
- Remember \(len_i=\frac{l_i+1}{2}\), it is not difficult to find that \(len_i\) is the length of the longest palindrome substring when only one side of the character is counted, that is, the number of palindrome strings .
- Now consider each query \([L,R]\), we turn it into a query \([L*2-1,R*2+1]\) in a new string, and then count only odd lengths The number of palindromic substrings of .
- Note that the answer to the original question is \(Ans\), the answer to the new question is \(New\), there is \(Ans=\frac{New-(R-L+2)}{2}\) (except \( R-L+2\) individual " # ", each string S of the original query corresponds to the two strings in the new query).
- Considering each palindrome center\(i\), if\(i-len_i+1≥L\)and\(i+len_i-1≤R\), then its contribution to the query answer is obviously\(len_i\ ), otherwise, a part of the palindrome centered on \(i\) will exceed the range of this interval, and we call \(i\) "limited".
- Remember \(Mid=\frac{L+R}{2}\), obviously the position in \([L,Mid]\) can only be "limited" by \(L\), while \([Mid+1 ,R]\) can only be "restricted" by \(R\).
- Divide the query into two parts, \([L,Mid]\) and \([Mid+1,R]\), and process them separately. Due to the symmetry of the processing method, we only discuss the \([L,Mid]\) below. part.
- What we are asking for is actually \(\sum_{i=L}^{Mid}([i-len_i+1≥L]*len_i+[i-len_i+1<L]*(i-L+1))\ ).
- Taking the query offline and sorting it according to \(L\), it is not difficult to use the tree array to obtain the value of the above formula.
- Time complexity\(O((N+Q)LogN)\).
【Code】
#include<bits/stdc++.h> using namespace std; const int MAXN = 300005; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct querys {int pos, home; }; vector <querys> l[MAXN], r[MAXN]; char s[MAXN]; int n, q, len[MAXN]; long long ans[MAXN]; struct BinaryIndexTree { int n; long long a[MAXN]; void init(int x) { n = x; memset(a, 0, sizeof(a)); } void modify(int pos, int x) { for (int i = pos; i <= n; i += i & -i) a[i] += x; } long long query(int pos) { long long ans = 0; for (int i = pos; i >= 1; i -= i & -i) years += a[i]; return ans; } } Inside, Sum, Cnt; void solvel() { Inside.init(n); Sum.init(n), Cnt.init(n); static vector <int> dis[MAXN]; for (int i = 1; i <= n; i++) { Inside.modify(i, len[i]); dis[i - len[i] + 1].push_back(i); } for (int i = 1; i <= n; i++) { for (unsigned j = 0; j < l[i].size(); j++) { long long tans = 0; tans += Inside.query(l[i][j].pos); tans += Sum.query(l[i][j].pos) - Cnt.query(l[i][j].pos) * (i - 1); ans[l[i][j].home] += tans; } for (unsigned j = 0; j < dis[i].size(); j++) { int tmp = dis[i][j]; Inside.modify(tmp, -len[tmp]); Sum.modify(tmp, tmp); Cnt.modify(tmp, 1); } Sum.modify(i, -i); Cnt.modify(i, -1); } } void solver() { Inside.init(n); int m = n + 1; Sum.init(n), Cnt.init(n); static vector <int> dis[MAXN]; for (int i = 1; i <= n; i++) { Inside.modify(m - i, len[i]); dis[i + len[i] - 1].push_back(i); } for (int i = n; i >= 1; i--) { for (unsigned j = 0; j < r[i].size(); j++) { long long tans = 0; tans += Inside.query(m - r[i][j].pos); tans += Cnt.query(m - r[i][j].pos) * (i + 1) - Sum.query(m - r[i][j].pos); ans[r[i][j].home] += tans; } for (unsigned j = 0; j < dis[i].size(); j++) { int tmp = dis[i][j]; Inside.modify(m - tmp, -len[tmp]); Sum.modify(m - tmp, tmp); Cnt.modify(m - tmp, 1); } Sum.modify(m - i, -i); Cnt.modify(m - i, -1); } } int main() { scanf("%s", s + 1); n = strlen(s + 1); for (int i = n; i >= 1; i--) s[i * 2] = s[i]; for (int i = 0; i <= n; i++) s[i * 2 + 1] = '#'; s[0] = '$', s[n * 2 + 2] = '%'; n = n * 2 + 1; int pos = 0, home = 0; for (int i = 1; i <= n; i++) { if (i <= pos) { int j = 2 * home - i; len [i] = min (len [j], pos - i); } while (s[i + len[i]] == s[i - len[i]]) len[i]++; if (i + len[i] - 1 >= pos) { pos = i + len [i] - 1; home = i; } } read(q); for (int i = 1; i <= q; i++) { int x, y, z; read(x), read(y); ans[i] = -(y - x + 2); x = 2 * x - 1; y = 2 * y + 1; z = (x + y) / 2; l[x].push_back((querys) {z, i}); r[y].push_back((querys) {z + 1, i}); } solvel(); solver(); for (int i = 1; i <= q; i++) writeln(ans[i] / 2); return 0; }