bzoj 3160: 万径人踪灭 — FFT,manacher
3160: 万径人踪灭
Time Limit: 10 Sec Memory Limit: 256 MB
Description
Source
不难发现,ans=总方案 – 连续子串
考虑总方案,枚举对称轴,方案数就是2^f(i) -1,f(i) 表示有多少对关于对称轴对称
那么如何求f(i),
很容易发现式子就是FFT卷积,那就把a,b拆开分别求一遍FFT就好了
连续的就直接manacher咯
#include<map> #include<cmath> #include<queue> #include<cstdio> #include<string> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define mod 1000000007 #define ll long long #define N 200010 #define PI 3.141592653589793 struct cp{ double r,i; cp(double _r=0,double _i=0):r(_r),i(_i){} cp operator + (cp x){return cp(r+x.r,i+x.i);} cp operator - (cp x){return cp(r-x.r,i-x.i);} cp operator * (cp x){return cp(r*x.r-i*x.i,r*x.i+i*x.r);} void clr(){r=i=0.0;} }; cp A[N],B[N]; int r[N],L=-1; void FFT(cp *x,int n,int f) { register int i,j,k; for(i=0;i<n;i++) if(i<r[i]) swap(x[i],x[r[i]]); for(i=1;i<n;i<<=1) { cp wn(cos(PI/i),f*sin(PI/i)); for(j=0;j<n;j+=i<<1) { cp w(1,0),X,Y; for(k=0;k<i;k++,w=w*wn) { X=x[k+j];Y=w*x[k+j+i]; x[k+j]=X+Y;x[k+j+i]=X-Y; } } } if(f==-1) for(int i=0;i<n;i++) x[i].r/=n; } char s[N],a[N]; int n,m,sum,ans; int mx,md,p[N]; void manc() { for(int i=1;i<=n;i++) { a[i<<1]=s[i]; a[i<<1|1]='#'; } int nn=n+1<<1;a[0]='!'; a[1]='#';a[nn]='&'; for(int i=1;i<=nn;i++) { if(mx>=i) p[i]=min(mx-i,p[2*md-i]); else p[i]=1; while(a[i-p[i]]==a[i+p[i]]) p[i]++; if(i+p[i]>mx) mx=i+p[i],md=i; } for(int i=2;i<nn;i++) (sum+=p[i]>>1)%=mod; } int ksm(ll a,int b) { ll sum=1; while(b) { if(b&1) sum=sum*a%mod; a=a*a%mod;b>>=1; } return sum; } int main() { scanf("%s",s+1); n=strlen(s+1); manc(); for(int i=0;i<n;i++) { if(s[i+1]=='a') A[i].r=1; else B[i].r=1; } for(m=1;m<(n<<1);m<<=1) L++; for(int i=0;i<m;i++) r[i]=r[i>>1]>>1|((i&1)<<L); FFT(A,m,1);FFT(B,m,1); for(int i=0;i<m;i++) { A[i]=A[i]*A[i]; B[i]=B[i]*B[i]; } FFT(A,m,-1);FFT(B,m,-1); for(int i=0,x;i<n+n-1;i++) { x=(int)(A[i].r+0.1)+(int)(B[i].r+0.1); x=x+1>>1; ans+=ksm(2,x)-1; ans%=mod; } printf("%d\n",(ans-sum+mod)%mod); return 0; }
发表评论