题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3160
题目分析:感觉这题就是在UVALive4671那题的基础上强加了个Manacher……
两个位置对称,就意味着它们下标的和相等。于是我们先将字符串中所有a变为1,其余位置变为0,做一次自乘。如果有两个位置都是a,并且它们沿第X位对称,那么它们就会对得式的第2X位有贡献;如果它们沿第X,X+1位中间的夹缝对称,那么它们就会对得式的第2X+1位有贡献。然后再将b设为1,其余位置设为0,同样做一次FFT,就可以知道沿某个位置(夹缝)对称的位置有多少对了。如果沿某个位置(夹缝)对称的有n对位置,那么它对答案的贡献显然为 2n−1 ,可以预处理2的幂。不合法的情况用Manacher减去就好了。
CODE:
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=300000;
const long long M=1000000007;
const double pi=acos(-1.0);
typedef long long LL;
struct Complex
{
double X,Y;
Complex (double a=0.0,double b=0.0) : X(a),Y(b) {}
} ;
Complex operator+(Complex a,Complex b){return Complex(a.X+b.X,a.Y+b.Y);}
Complex operator-(Complex a,Complex b){return Complex(a.X-b.X,a.Y-b.Y);}
Complex operator*(Complex a,Complex b){return Complex(a.X*b.X-a.Y*b.Y,a.X*b.Y+a.Y*b.X);}
int Rev[maxn];
Complex A[maxn];
int num[maxn];
int ans[maxn];
int val[maxn];
int cnt[maxn];
LL Pow[maxn];
char s[maxn];
int n,N,Lg;
void Preparation()
{
N=1,Lg=0;
while (N<2*n) N<<=1,Lg++;
for (int i=0; i<N; i++)
for (int j=0; j<Lg; j++)
if ( i&(1<<j) ) Rev[i]|=( 1<<(Lg-j-1) );
Pow[0]=1;
for (int i=1; i<maxn; i++) Pow[i]=(Pow[i-1]<<1)%M;
for (int i=0; i<maxn; i++) Pow[i]=(Pow[i]-1LL+M)%M;
}
void DFT(Complex *a,double f)
{
for (int i=0; i<N; i++)
if (i<Rev[i]) swap(a[i],a[ Rev[i] ]);
for (int len=2; len<=N; len<<=1)
{
int mid=len>>1;
double ang=2.0*pi/((double)len);
Complex e( cos(ang) , f*sin(ang) );
for (Complex *p=a; p!=a+N; p+=len)
{
Complex wn(1.0,0.0);
for (int i=0; i<mid; i++)
{
Complex temp=wn*p[mid+i];
p[mid+i]=p[i]-temp;
p[i]=p[i]+temp;
wn=wn*e;
}
}
}
}
void FFT(int x)
{
for (int i=0; i<n; i++)
if (val[i]==x) A[i]=Complex(1.0,0.0);
else A[i]=Complex(0.0,0.0);
for (int i=n; i<N; i++) A[i]=Complex(0.0,0.0);
DFT(A,1.0);
for (int i=0; i<N; i++) A[i]=A[i]*A[i];
DFT(A,-1.0);
for (int i=0; i<N; i++) A[i].X/=((double)N);
for (int i=0; i<N; i++) cnt[i]+=( (int)floor( A[i].X+0.5 ) );
}
void Manacher()
{
num[0]=4;
for (int i=0; i<n; i++) num[(i<<1)|1]=val[i],num[(i<<1)+2]=3;
num[n<<1]=5;
ans[0]=ans[1]=0;
int p=1;
for (int i=2; i<=2*n; i++)
{
int temp=max( min(p+ans[p]-i,ans[2*p-i]) , 0 );
while ( num[i-temp-1]==num[i+temp+1] ) temp++;
ans[i]=temp;
if (i+ans[i]>p+ans[p]) p=i;
}
}
int main()
{
freopen("3160.in","r",stdin);
freopen("3160.out","w",stdout);
scanf("%s",s);
n=strlen(s);
for (int i=0; i<n; i++) val[i]=s[i]-'a';
Preparation();
FFT(0);
FFT(1);
for (int i=0; i<N; i++) cnt[i]=(cnt[i]+1)/2;
Manacher();
int Ans=0;
for (int i=0; i<N; i++) Ans=(Ans+Pow[ cnt[i] ])%M;
for (int i=1; i<=2*n; i+=2) Ans=(Ans-(ans[i]/2+1)+M)%M;
for (int i=0; i<2*n; i+=2) Ans=(Ans-((ans[i]+1)>>1)+M)%M;
printf("%d\n",Ans);
return 0;
}