版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kidsummer/article/details/82083413
题意描述
给定一个字符串,统计有多少个子串是one−and−half palindromicone−and−half palindromic. (即字符串长度为3n−23n−2,且满足S[i]=S[2n−i]=S[2n+i−2](1≤i≤n)S[i]=S[2n−i]=S[2n+i−2](1≤i≤n)。
数据范围:字符串长度小于等于500000500000.
思路:
这个题目说了,所有的回文串都是奇数个,所以,我们已经不需要在添加字符了。直接在原串中用马拉车。
马拉车为什么要添加字符。就是为了要把回文串变成奇数个。
-----i----j------
要满足题目中的条件。我们就要找两个回文串,他们的回文长度相交就行。
这里,我的p[i]代表 i 的一半回文长度,包含 i ,就是总长度+1 / 2;
满足题目的长度,我们要满足以下条件。
1、 i < j
2、 i > j - p[j]
3、 j < i + p[i]
我们先做一遍 马拉车,找到了 p[i], 然后根据 第 2 条。找 j - p[j] < i 的数。我们先按 j - p[j] 从小到大排序,
吧 j - p[j] 的数的位置 j 插入到树状数组中去。然后找 i+1 ~ i + p[j]-1 这个区间的 j 有多少个。
#include <bits/stdc++.h>
#define mem(x,v) memset(x,v,sizeof(x))
#define go(i,a,b) for (int i = a; i <= b; i++)
#define og(i,a,b) for (int i = a; i >= b; i--)
#define low(x) (x & (-x))
#define X first
#define Y second
using namespace std;
typedef long long LL;
typedef pair<int,int> P;
const double EPS = 1e-10;
const int INF = 0x3f3f3f3f;
const int N = 6e5+10;
char t[N];
int len,p[N],c[N];
void Add(int x){
while(x <= len) c[x]++,x += low(x);
}
LL Query(int x){
LL ans = 0;
while(x > 0) ans += c[x], x -= low(x);
return ans;
}
void Manacher(){
scanf("%s",t+1);
len = strlen(t+1);
int id = 0,mx = 0;
for (int i = 1; i <= len; i++){
p[i] = mx > i?min(p[2*id-i],mx-i):1;
while(t[i-p[i]] == t[i+p[i]]) p[i]++;
if (mx < i+ p[i]){
id = i;
mx = i + p[i];
}
}
return;
}
int main(){
int T; cin>>T;
while(T--){
mem(c,0);
mem(p,0);
Manacher();
priority_queue<P,vector<P>,greater<P> >Q;
go(i,1,len) Q.push(P(i-p[i],i));
LL sum = 0;
go(i,1,len){
while(!Q.empty() && Q.top().X < i){
P u = Q.top(); Q.pop();
Add(u.Y);
}
sum += (Query(i+p[i]-1)-Query(i));
}
printf("%I64d\n",sum);
}
return 0;
}