版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_38081836/article/details/83419114
题意:给出一个字符串,询问有多少个双回文(形如-----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;
}