题意:已知一个长度为n的字符串仅由’a’和’b’构成,求该串不连续的回文子串个数。
严格地描述,题意中的回文子串应满足:
1.位置和字符都关于某条线对称
2.该回文串不连续
解法:FFT+manacher
1.先求连续区间内的回文子串个数ans1。用manacher算法可以得到
2.再求所有连续子串个数。将字符串增倍(每个字符之间加入#字符),设f[i]:在倍增串中以第i个字符为中心且出现在原字符串中的对称字符的对数。
结论:f[i]=
((∑len−1j=0ch[j]==ch[i−j])+1)>>1
即在倍增串中以第i位字符为中心时,原串中下标和为i的相同字符对f[i]有贡献。
3.以倍增串中第i个字符为对称轴的对称回文串个数为
2f[i]
-1
4.ans=
(∑(2f[i]−1))−ans1
#include <stdio.h>
#include <string.h>
#include <set>
#include <map>
#include <algorithm>
#include<complex>
#include<iostream>
#define pi acos(-1)
#define ll long long
using namespace std ;
typedef complex<double> E;
const int mod = 1000000007;
const int maxn = 300000+10;
char ch[maxn];
int len;
E a[maxn],b[maxn];//a是乘积前的系数数组 b是乘积后的系数数组 赋值到c数组中
int n,m,L;
int R[maxn],c[maxn],p[maxn];
ll ans,bin[maxn];
void fft(E *a,int f){
for(int i=0;i<n;i++) if(i<R[i]) swap(a[i],a[R[i]]);
for(int i=1;i<n;i<<=1){
E wn(cos(pi/i),f*sin(pi/i));
for(int p=i<<1,j=0;j<n;j+=p){
E w(1,0);
for(int k=0;k<i;k++,w*=wn){
E x=a[j+k],y=w*a[j+k+i];
a[j+k]=x+y; a[j+k+i]=x-y;
}
}
}
if(f==-1) for(int i=0;i<n;i++) a[i]/=n;
}
void manacher(){
ch[0]='-',ch[len+1]='+';//字符串首尾得空出来!
int id,mx=0;
memset(p,0,sizeof(p));
for(int i=1;i<=len;i++){
if(mx>i) p[i]=min(mx-i+1,p[2*id-i]);
else p[i]=1;
while(ch[i+p[i]]==ch[i-p[i]]) p[i]++;
if(i+p[i]-1>mx) mx=i+p[i]-1,id=i;
ans=((ans-p[i])%mod+mod)%mod;
}
mx=0;
for(int i=1;i<=len;i++){
if(mx>i) p[i]=min(mx-i,p[2*id-i]);
else p[i]=0;
while(ch[i+p[i]+1]==ch[i-p[i]]) p[i]++;
if(i+p[i]>mx) mx=i+p[i],id=i;
ans=((ans-p[i])%mod+mod)%mod;
}
}
int main(){
//freopen("a.txt","r",stdin);
//求2的i次幂
bin[0]=1; for(int i=1;i<=maxn;i++) bin[i]=(bin[i-1]*2)%mod;
scanf("%s",ch+1);
len=strlen(ch+1);
ans=0;
//先求连续的回文子串的个数
manacher();
//初始化n,m,l,R[]
n=len-1; m=2*n; L=0;
for(n=1;n<=m;n<<=1) L++;
for(int i=1;i<n;i++) R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
//初始化a多项式系数数组 并求FFT和a*a多项式值表达式
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=0;i<len;i++) a[i]=(ch[i+1]=='a');
fft(a,1);
for(int i=0;i<=n;i++) b[i]=a[i]*a[i];
//重新初始化a多项式系数数组 并求FFT和a*a多项式值表达式
memset(a,0,sizeof(a));
for(int i=0;i<len;i++) a[i]=(ch[i+1]=='b');
fft(a,1);
for(int i=0;i<=n;i++) b[i]+=a[i]*a[i];
//求FFT逆变换 并求各幂次对应系数
fft(b,-1);
for(int i=0;i<=m;i++) c[i]=b[i].real()+0.1;
//求结果
for(int i=0;i<=m;i++)
ans=((ans+bin[(c[i]+1)>>1]-1)%mod+mod)%mod;
printf("%lld\n",(ans+mod)%mod);
return 0;
}