[hdu 6230 Palindrome] Manacher+樹狀數組
分類:Data Structure
Manacher
FenwickedTree
1. 題目鏈接
2. 題意描述
給定一個字符串,統計有多少個子串是
數據範圍:字符串長度小於等於
3. 解題思路
對
首先,用Manacher預處理出每個字符爲中心的最長迴文串長度,
設子串中
那麼,該子串必然要滿足:
然後,再用樹狀數組計數統計。
4. 實現代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double lb;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ull, ull> puu;
typedef pair<lb, lb> pbb;
const int inf = 0x3f3f3f3f;
const ll infl = 0x3f3f3f3f3f3f3f3fLL;
template<typename T> inline void umax(T &a, T b) { a = max(a, b); }
template<typename T> inline void umin(T &a, T b) { a = min(a, b); }
template<typename T> inline T randIntv(const T& a, const T& b) { return (T)rand() % (b - a + 1) + a; }
#ifdef ___LOCAL_WONZY___
void debug() { cout << endl; }
template<typename T, typename ...R> void debug (T f, R ...r) { cout << "[" << f << "]"; debug (r...); }
#endif
const int MAXL = 500005;
char s[MAXL * 2];
int p[MAXL * 2], len1, len2;
/*
首先,i>=2 的 p 纔有意義
p[i]-1 爲以 i 爲中心的迴文長度
p[i]/2 表示迴文半徑
i%2==0 表示這個位置爲字符,i/2-1 表示原字符串的位置
i%2==1 表示爲字符中間,這兩邊的字符在原字符串的位置分別爲 i/2-1 和 i/2
*/
int manacher(char *s) {
int len = strlen(s), id = 0, ans = 0;
for (int i = len; i >= 0; i--) {
s[i + i + 2] = s[i];
s[i + i + 1] = '#';
}
s[0] = '*';
for (int i = 2; i < 2 * len + 1; ++i) {
if (p[id] + id > i) p[i] = min(p[2 * id - i], p[id] + id - i);
else p[i] = 1;
while (s[i - p[i]] == s[i + p[i]]) p[i]++;
if (id + p[id] < i + p[i]) id = i;
ans = max(ans, p[i] - 1);
}
return ans;
}
ll c[MAXL * 2];
void upd(int x, ll v) {
while (x <= len2) {
c[x] += v;
x += x & (-x);
}
}
ll qry(int x) {
ll ret = 0;
while (x > 0) {
ret += c[x];
x -= x & (-x);
}
return ret;
}
ll sum(int L, int R) { return qry(R) - qry(L - 1); }
void clr(int x) { upd(x, -sum(x, x)); }
int main() {
#ifdef ___LOCAL_WONZY___
freopen ("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
int T; scanf("%d", &T);
while (T --) {
scanf("%s", s);
len1 = strlen(s); len2 = len1 * 2 + 1;
manacher(s);
vector<pii> line;
for (int i = 2; i < len2; i += 2) {
int r = p[i] / 2, s = i - (r - 1) * 2;
if (r <= 1) continue;
line.push_back(pii(s, i));
}
sort(line.begin(), line.end());
memset(c, 0, sizeof(c));
ll ans = 0, p = 0;
for (int i = 2; i < len2; i += 2) {
clr(i);
int r = ::p[i] / 2, j = i + (r - 1) * 2;
if (r <= 1) continue;
while (p < line.size() && line[p].first <= i) {
upd(line[p].second, 1);
++ p;
}
ans += sum(i + 1, j);
}
printf("%lld\n", ans);
}
#ifdef ___LOCAL_WONZY___
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // ___LOCAL_WONZY___
return 0;
}