【HDU-6230/2017CCPC哈爾濱A】Palindrome(式子轉換+馬拉車+主席樹)
阿新 • • 發佈:2020-12-09
題目連結:https://vjudge.net/problem/HDU-6230、
題目大意
給定一個字串,求這個字串中有多少個一個半字串。
一個半字串:類似於1234543212345。
花絮
模擬賽時一直只思考了 123454321 怎麼通過 \(O(1)\) 的時間複雜度搞出後面的串,導致直接卡死。
思路
1234543212345 是按照5和1對稱的,那麼在保證5和1是迴文串的狀態下,要能夠之間相互覆蓋。
設5的位置為 \(i\),1的位置為 \(j\), 要求 \(i \leq j\),則可得公式
\( \left\{\begin{matrix} j-i \leq len[i] \\ j-i \leq len[j] \\ \end{matrix}\right. \)
移動式子,可得
\( \left\{\begin{matrix} j \leq i+len[i] \\ j-len[j] \leq i \\ \end{matrix}\right. \)
將其轉化為區間 \([i+1, i+len[i]]\) 內求有多少個數,使得 \(j-len[j] \leq i\)。
AC程式碼
#include <bits/stdc++.h> typedef long long ll; using namespace std; const int MAXN = 5e5 + 5; class HJT { public: int ch[MAXN * 70][2], sum[MAXN * 70]; int tot; void init() { tot = 0; } inline void push_up(int rt) { sum[rt] = sum[ch[rt][0]] + sum[ch[rt][1]]; } int update(int rt, int pos, int val, int be, int en) { int nrt = ++tot; ch[nrt][0] = ch[nrt][1] = sum[nrt] = 0; if (be == en) { sum[nrt] = sum[rt] + val; return nrt; } int mid = (be + en) >> 1; if (pos <= mid) { ch[nrt][0] = update(ch[rt][0], pos, val, be, mid); ch[nrt][1] = ch[rt][1]; } else { ch[nrt][0] = ch[rt][0]; ch[nrt][1] = update(ch[rt][1], pos, val, mid + 1, en); } push_up(nrt); return nrt; } int query(int lrt, int rrt, int R, int be, int en) { if (R == en) return sum[rrt] - sum[lrt]; int mid = (be + en) >> 1; if (R <= mid) { return query(ch[lrt][0], ch[rrt][0], R, be, mid); } else { return sum[ch[rrt][0]] - sum[ch[lrt][0]] + query(ch[lrt][1], ch[rrt][1], R, mid + 1, en); } } } tree; void Manacher(char s[], int len, char A[], int B[]) { int l = 0; A[l++] = '$'; A[l++] = '#'; for (int i = 0; i < len; i++) { A[l++] = s[i]; A[l++] = '#'; } A[l] = 0; int mx = 0, id = 0; for (int i = 0; i < l; i++) { B[i] = mx > i ? std::min(B[2 * id - i], mx - i) : 1; while (A[i + B[i]] == A[i - B[i]]) B[i]++; if (i + B[i] > mx) mx = i + B[i], id = i; } } char A[MAXN * 2]; int B[MAXN * 2]; char str[MAXN]; int ren[MAXN], root[MAXN]; int main() { int T; scanf("%d", &T); while (T--) { scanf("%s", str + 1); int n = strlen(str + 1); Manacher(str + 1, n, A + 1, B + 1); int maxR = 0; for (int i = 1; i <= n; i++) ren[i] = (B[i * 2 + 1] - 2) >> 1, maxR = max(maxR, i - ren[i]); tree.init(); root[0] = 0; for (int i = 1; i <= n; i++) { root[i] = tree.update(root[i - 1], i - ren[i], 1, 1, maxR); } ll res = 0; for (int i = 1; i <= n; i++) { if (ren[i] == 0) continue; // printf("%d %d %d %d\n", i, i, i+ren[i], tree.query(root[i], root[i+ren[i]], i, 1, maxR)); res = res + tree.query(root[i], root[i+ren[i]], i, 1, maxR); } printf("%lld\n", res); // for (int i = 1; i <= n; i++) { // printf("%d ", ren[i]); // } // printf("\n"); } }