Palindrome
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 329 Accepted Submission(s): 129
Problem Description
Alice like strings, especially long strings. For each string, she has a special evaluation system to judge how elegant the string is. She defines that a string
S[1..3n−2](n≥2)
is one-and-half palindromic if and only if it satisfies
S[i]=S[2n−i]=S[2n+i−2](1≤i≤n)
.For example,
abcbabc
is one-and-half palindromic string, and
abccbaabc
is not. Now, Alice has generated some long strings. She ask for your help to find how many substrings which is one-and-half palindromic.
Input
The first line is the number of test cases. For each test case, there is only one line containing a string(the length of strings is less than or equal to
500000
), this string only consists of lowercase letters.
Output
For each test case, output a integer donating the number of one-and-half palindromic substrings.
Sample Input
1 ababcbabccbaabc
Sample Output
2HintIn the example input, there are two substrings which are one-and-half palindromic strings, $abab$ and $abcbabc$.
Source
题意:字符串S【1,3n-2】 中以 位置n(C1)和2n-1(C2)为回文串中心,长度都为n,找出给出的主串中有多少这样的子串
分析:首先用manacher求出以每个点为中心的回文串半径,考虑每个点作为C1时,有多少位置作为C2可以组成字符串S, 位置 i 的回文串长度为leni,统计多少第k (i<=k<=i+leni)位置的k-lenk是否小于i。所以我们用主席树实现,每个位置存下权值 i - leni,每次求 第i位置作为C1 时 求出 区间【i,i+leni】中权值小于 i 的数量。
代码:
#include<bits/stdc++.h>
#define maxn 500005
using namespace std;
int f[maxn],len;
int tot,root[maxn*30],ls[maxn*30],rs[maxn*30];
long long sum[maxn*30];
char s[maxn];
void Manacher(){
len=strlen(s+1);
int mx=1,p=1;
s[0]='#';
for(int i=1;i<=len;i++){
if(mx>i) f[i]=min(mx-i,f[2*p-i]);
else f[i]=0;
while(s[i+f[i]+1]==s[i-f[i]-1]) f[i]++;
if(f[i]+i>mx){
mx=f[i]+i;
p=i;
}
}
return;
}
void update(int k,int pre,int &now,int l,int r){
now=++tot;
ls[now]=ls[pre];
rs[now]=rs[pre];
sum[now]=sum[pre]+1;
if(l==r){
return;
}
int m=(l+r)>>1;
if(k<=m) update(k,ls[pre],ls[now],l,m);
else update(k,rs[pre],rs[now],m+1,r);
}
long long query(int L,int R,int r1,int r2,int l,int r){
if(L<=l && r<=R){
//cout<<sum[r1]<<" "<<sum[r2]<<endl;
return sum[r1]-sum[r2];
}
int m=(l+r)>>1;
long long cou=0;
if(L<=m) cou+=query(L,R,ls[r1],ls[r2],l,m);
if(R>m) cou+=query(L,R,rs[r1],rs[r2],m+1,r);
return cou;
}
int main(){
int t;
cin>>t;
while(t--){
scanf("%s",s+1);
Manacher();
long long ans=0;
tot=0;
root[0]=ls[0]=rs[0]=sum[0]=0;
for(int i=1;i<=len;i++){
if(f[i])update(i-f[i],root[i-1],root[i],1,len);
else root[i]=root[i-1];
}
for(int i=1;i<=len;i++){
if(f[i])ans+=query(1,i,root[i+f[i]],root[i],1,len);
}
cout<<ans<<endl;
}
return 0;
}