A - Palindrome HDU - 6230[馬拉車+bit]
阿新 • • 發佈:2018-11-07
題意:給出一個字串,詢問有多少個雙迴文(形如-----i-----j-----)i,j為對稱中心。
題解:可以使用馬拉車演算法預處理出每個字元為對稱中心的迴文串長度,然後通過樹狀陣列維護下面的關係
首先補充一些關於馬拉車的一些性質:
- 原陣列與轉換之後的陣列位置的對應為
- p[i - 1]表示以i為中心的迴文串長度
- p[i]/2表示以i為中心的迴文半徑
我們可以通過遍歷字串的p陣列來得到以它為中心向左可以最長延伸到哪也就是第二個條件,第一個條件在遍歷更新bit的過程中已經滿足,接下來就是利用bit查詢能夠延伸到右邊的有多少個,然後相加即為結果。
收穫:
- 樹狀陣列竟然可以維護不等式關係!
- 馬拉車性質的理解
/****陣列大小****/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define debug cerr << "*" << endl;
#define rep(i, a, b) for(int i = a; i <= b; i++)
#define pre(i, a, b) for(int i = a; i >= b; i--)
#define met(a, b) memset(a, b, sizeof(a))
const int maxn = 1e6 + 10;
const int inf = 0x3f3f3f3f;
char s[maxn << 1], tmp[maxn << 1];
ll p[maxn << 1];
void init(char *s) {
int len = strlen(s);
tmp[0] = '@';
tmp[1] = '#';
int j = 2;
for(int i = 0; i < len; i++) {
tmp[j++] = s[i];
tmp[j++] = '#';
}
tmp[j++] = '\0';
}
int manacher(char *s) {
ll maxLen = 1;
ll id = 0, mx = 0;
ll len = strlen(s);
for(int i = 0; i < len; i++) {
if(i < mx) p[i] = min(p[2 * id - i], mx - i);
else p[i] = 1;
while(s[i + p[i]] == s[i - p[i]]) {
p[i]++;
}
if(i + p[i] > mx) {
mx = i + p[i];
id = i;
}
maxLen = max(maxLen, p[i] - 1);
}
return maxLen;
}
ll c[maxn << 1];
ll lowbit(ll x) {
return x & (-x);
}
void upd(ll pos, ll x) {
while(pos < maxn) {
c[pos] += x;
pos += lowbit(pos);
//cout << pos <<endl;
}
}
ll query(ll pos) {
ll res = 0;
while(pos > 0) {
res += c[pos];
pos -= lowbit(pos);
}
return res;
}
vector<ll> g[maxn];
ll pp[maxn];
int main() {
//cerr << "hqx is the best man!!" << endl;
int T;
scanf("%d", &T);
while(T--) {
met(c, 0);
met(p, 0);
scanf("%s", s);
init(s);
manacher(tmp);
ll len = strlen(tmp);
for(int i = 0; i < maxn; i++) g[i].clear();
int k = 1;
for(int i = 2; i < len; i += 2) {
pp[k] = p[i] / 2 - 1;
g[k - pp[k]].push_back(k);
k++;
}
len = strlen(s);
ll ans = 0;
rep(i, 1, len) {
rep(j, 0, (int)g[i].size() - 1) {
upd(g[i][j], 1);
}
ans += query(min(pp[i] + i, len)) - query(i);
//cerr << ans << endl;
}
printf("%lld\n", ans);
}
return 0;
}