我是真的想写字符串的题。。。
这道题除了manacher和字符串有半!毛!钱!关!系!
题目所求的数量可以由(无限制对称字符串)-(连续对称字符串)求得
其中(连续对称字符串)可以由manacher求得,问题变为求(无限制对称字符串)的数量
我们考虑d[i]表示s[a]==s[b]&&a+b==i的数的对数(ab可以相等并且ab有序),那么sum=sigma(2^( ( d[i] - 1 ) / 2))
现在的问题是如何求d[i]
首先不难想到n^2的算法,然后发现d[i]是一个卷积的形式,假设我们要求同为a的d[i],就做一个n次多项式A,a[i]= s[i]=='a'?1:0 d[i]就相当于A^2中次数为i的项的次数,因此我们可以用FFT进行优化。
#include<cstdlib> #include<cstdio> #include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; #define maxn 400005 #define pi 3.14159265358979323846264338327950388419716939937530 #define mo 1000000007 char s0[maxn],s[3*maxn]; int cnt,n,d[3*maxn]; void Init() { scanf("%s",s0); n=strlen(s0);cnt=0; cnt++; s[0]='$'; s[cnt]='#'; for(int i=0;i<n;i++) { s[++cnt]=s0[i]; s[++cnt]='#'; } d[0]=0; int maxi=0; for(int i=1;i<=cnt;i++) { if(i<=maxi+d[maxi]-1)d[i]=min(d[2*maxi-i],maxi+d[maxi]-i); while(s[i+d[i]]==s[i-d[i]])d[i]++; if(i+d[i]>=maxi+d[maxi])maxi=i; } s[cnt+1]='\0'; /* printf("%s\n",s+1); for(int i=1;i<=cnt;i++) { printf("%d",d[i]); } putchar('\n');*/ return ; } struct _My_Complex { double i,j; _My_Complex() {} _My_Complex(double c,double cc) : i(c),j(cc) {} void operator +=(_My_Complex a) { i+=a.i; j+=a.j; } friend _My_Complex operator + (_My_Complex a, _My_Complex b) { return _My_Complex(a.i+b.i,a.j+b.j); } friend _My_Complex operator - (_My_Complex a, _My_Complex b) { return _My_Complex(a.i-b.i,a.j-b.j); } friend _My_Complex operator * (_My_Complex a, _My_Complex b) { return _My_Complex(a.i*b.i-a.j*b.j,a.i*b.j+a.j*b.i); } }u,t; _My_Complex a[maxn*2],b[maxn*2]; bool v[maxn*2]; int c; void FFT(_My_Complex *x,int l,int on) { for(int i=0;i<l;i++) { int j=0; for(int w=0;w<c;w++)if((1<<w)&i) { j|=(1<<(c-1-w)); } if(i<j)swap(x[i],x[j]); } for(int k=2;k<=l;k=k*2) { _My_Complex wn(cos((double)on*2*pi/k),sin((double)on*2*pi/k)); for(int j=0;j<l;j+=k) { _My_Complex w(1.0,0.0); for(int i=j;i<j+k/2;i++) { u=x[i]; t=x[i+k/2]*w; x[i]=u+t; x[i+k/2]=u-t; w=w*wn; } } } if(on==-1) { for(int i=0;i<l;i++)x[i].i=x[i].i/l; } return ; } int l; int ans,B[maxn],C[maxn]; void work() { B[0]=1; for(int i=1;i<=100000;i++)B[i]=(B[i-1]*2)%mo; l=1;c=0; while(l<n*2)l=l*2,c++; for(int i=0;i<n;i++) { a[i].i= s0[i]=='a'? 1.0:0.0;a[i].j=0; } for(int i=n;i<l;i++) { a[i].i= 0.0;a[i].j=0; } FFT(a,l,1); for(int i=0;i<l;i++) { b[i]=a[i]*a[i]; } FFT(b,l,-1); ans=0; int hh; for(int i=0;i<l;i++) { hh=(int)(b[i].i+0.5); C[i]=C[i]+hh; } for(int i=0;i<n;i++) { a[i].i= s0[i]=='a'? 0.0:1.0;a[i].j=0; } for(int i=n;i<l;i++) { a[i].i= 0.0;a[i].j=0; } FFT(a,l,1); for(int i=0;i<l;i++) { b[i]=a[i]*a[i]; } FFT(b,l,-1); for(int i=0;i<l;i++) { hh=(int)(b[i].i+0.5); C[i]=C[i]+hh; } for(int i=0;i<l;i++) { // printf("%d ",C[i]); hh=C[i]; ans=ans+B[(hh+1)/2]-1-d[i+2]/2; ans=ans%mo; } ans=(ans%mo+mo)%mo; printf("%d\n",ans); return ; } int main() { freopen("in.txt","r",stdin); Init(); work(); return 0; }