3160: 万径人踪灭
Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 856 Solved: 487
[Submit][Status][Discuss]
Description
最后的答案可以表示成所有的回文子串的个数减去连续的回文串的个数。
后面的那个显然可以用
manacher
。前面的那个东西可以这样求:
设
f[i]
表示以
i
这个字符为中心的回文子串的个数。
那么
让
a,b
分别等于
0
或
很明显这是一个卷积的形式,做两遍
FFT
就行了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define Mod 1000000007
const int M=400000;
char s[M],ch[M];
int n,rev[M],dig[M],N,L,f[M],Pow[M],ans,p[M];
struct S{
double x,y;
S operator + (const S &xx){return (S){x+xx.x,y+xx.y};}
S operator - (const S &xx){return (S){x-xx.x,y-xx.y};}
S operator * (const S &xx){return (S){x*xx.x-y*xx.y,x*xx.y+y*xx.x};}
}a[M],c[M],d[M];
inline void FFT(S *a,int f){
int i,j,k;
S w,wn,x,y;
for(i=0;i<N;++i) d[i]=a[rev[i]];
for(i=0;i<N;++i) a[i]=d[i];
for(i=2;i<=N;i<<=1){
wn=(S){cos(2*M_PI/i),f*sin(2*M_PI/i)};
for(j=0;j<N;j+=i){
w=(S){1,0};
for(k=j;k<j+i/2;++k){
x=a[k];
y=w*a[k+i/2];
a[k]=x+y;
a[k+i/2]=x-y;
w=w*wn;
}
}
}
if(f==-1) for(i=0;i<N;++i) a[i].x/=(double)N;
}
inline int manacher(){
int maxn=1,id=1,sum=0,i;
for(ch[0]='$',ch[1]='#',i=1;i<=n;++i)
ch[i<<1]=s[i-1],ch[i<<1|1]='#';
for(i=1;i<=(n<<1|1);++i){
p[i]=min(maxn-i,p[id*2-i]);
while(ch[i+p[i]]==ch[i-p[i]]) ++p[i];
if(p[i]+i>maxn) maxn=p[i]+i,id=i;
sum=(sum+p[i]/2)%Mod;
}
return sum;
}
int main(){
int i,len,j;
scanf("%s",s);
n=strlen(s);
for(L=0,N=1;N<n;N<<=1,L+=1); N<<=1;L+=1;
for(i=0;i<N;++i){
for(j=i,len=0;j;j>>=1) dig[len++]=j&1;
for(j=0;j<L;++j) rev[i]=rev[i]*2+dig[j];
}
for(i=0;i<n;++i)
if(s[i]=='a') a[i]=(S){1.,0.};
FFT(a,1);
for(i=0;i<N;++i) c[i]=a[i]*a[i];
memset(a,0,sizeof(a));
for(i=0;i<n;++i)
if(s[i]=='b') a[i]=(S){1.,0.};
FFT(a,1);
for(i=0;i<N;++i) c[i]=c[i]+a[i]*a[i];
FFT(c,-1);
ans=Mod-manacher();
for(Pow[0]=1,i=1;i<N;++i) Pow[i]=Pow[i-1]*2%Mod;
for(i=0;i<N;++i){
f[i]=(c[i].x+0.5);
ans=(ans+Pow[(f[i]+1)>>1]-1)%Mod;
}
printf("%d\n",ans);
}