【BZOJ3160】万径人踪灭 FFT manacher

来源:互联网 发布:mac怎么删除flash 编辑:程序博客网 时间:2024/06/18 11:22

我是真的想写字符串的题。。。

这道题除了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 1000000007char 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;}


 

0 0
原创粉丝点击