BZOJ 3160: 万径人踪灭

题解

算出所有的回文子序列减去连续的

先在中间插好*

用f[i]表示以i为对称中心的对称位置有多少对

位置i的贡献为2f[i]-1

然后用manacher算不合法的

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 using namespace std;
  6 const int maxn=600009;
  7 const double pi=acos(-1.0);
  8 const int mm=1000000007;
  9 
 10 int n;
 11 char T[maxn];
 12 long long ans=0;
 13 long long ft[maxn];
 14 
 15 struct Cpx{
 16     double x,y;
 17     Cpx(){
 18         x=y=0.0;
 19     }
 20     Cpx(double xx,double yy){
 21         x=xx;y=yy;
 22     }
 23 }Pa[maxn];
 24 
 25 Cpx operator + (Cpx z1,Cpx z2){
 26     return Cpx(z1.x+z2.x,z1.y+z2.y);
 27 }
 28 Cpx operator - (Cpx z1,Cpx z2){
 29     return Cpx(z1.x-z2.x,z1.y-z2.y);
 30 }
 31 Cpx operator * (Cpx z1,Cpx z2){
 32     return Cpx(z1.x*z2.x-z1.y*z2.y,z1.x*z2.y+z2.x*z1.y);
 33 }
 34 
 35 int rev[maxn]={0};
 36 void FFT(Cpx *arr,int n,int f){
 37     int b=0;
 38     for(int len=1;len<n;len<<=1)b++;
 39     for(int i=0;i<n;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(b-1));
 40     
 41     for(int i=0;i<n;++i)if(i<rev[i])swap(arr[i],arr[rev[i]]);
 42     
 43     for(int k=1;k<n;k<<=1){
 44         int p=k+k;
 45         Cpx wn=Cpx(cos(pi/k),f*sin(pi/k));
 46         for(int i=0;i<n;i+=p){
 47             Cpx w=Cpx(1.0,0.0);
 48             for(int j=0;j<k;++j,w=w*wn){
 49                 Cpx x=arr[i+j],y=w*arr[i+j+k];
 50                 arr[i+j]=x+y;
 51                 arr[i+j+k]=x-y;
 52             }
 53         }
 54     }
 55     if(f==-1){
 56         for(int i=0;i<n;++i)arr[i].x=arr[i].x/(n*1.0);
 57     }
 58 }
 59 
 60 
 61 char s[maxn];
 62 int p[maxn]={0};
 63 void Manacher(int n){
 64     int mxlen=0,mxpla=0;
 65     for(int i=1;i<=n;++i){
 66         if(mxpla+mxlen>i){
 67             p[i]=min(mxpla+mxlen-i,p[mxpla*2-i]);
 68         }
 69         while(s[i-p[i]]==s[i+p[i]])++p[i];
 70         if(i+p[i]>mxpla+mxlen){
 71             mxpla=i;mxlen=p[i];
 72         }
 73     }
 74 }
 75 
 76 int f[maxn];
 77 
 78 int main(){
 79     scanf("%s",T+1);
 80     int len=strlen(T+1);
 81     s[++n]='*';
 82     for(int i=1;i<=len;++i){
 83         s[++n]=T[i];
 84         s[++n]='*';
 85     }
 86     s[++n]='#';
 87     
 88     
 89     for(len=1;len<=(n*2);len<<=1);
 90     for(int i=0;i<len;++i){
 91         Pa[i].x=Pa[i].y=0.0;
 92         if(s[i]=='a')Pa[i].x=1.0;
 93     }
 94 //    for(int i=0;i<len;++i)cout<<Pa[i].x<<' ';
 95 //    cout<<endl;
 96     FFT(Pa,len,1);
 97     
 98     for(int i=0;i<len;++i)Pa[i]=Pa[i]*Pa[i];
 99     FFT(Pa,len,-1);
100 //    for(int i=0;i<len;++i)printf("%.0f ",Pa[i].x);
101 //    cout<<endl;
102     for(int i=1;i<=n;++i){
103         int t=(int)(Pa[i*2].x+0.5);
104         f[i]+=(t+1)/2;
105     }
106     
107     for(int i=0;i<len;++i){
108         Pa[i].x=Pa[i].y=0.0;
109         if(s[i]=='b')Pa[i].x=1.0;
110     }
111     FFT(Pa,len,1);
112     for(int i=0;i<len;++i)Pa[i]=Pa[i]*Pa[i];
113     FFT(Pa,len,-1);
114     for(int i=1;i<=n;++i){
115         int t=(int)(Pa[i*2].x+0.5);
116         f[i]+=(t+1)/2;
117     }
118     
119     Manacher(n);
120     
121 //    for(int i=1;i<=n;++i)cout<<p[i]<<' ';
122 //    cout<<endl;
123     
124     ft[0]=1;
125     for(int i=1;i<=n;++i)ft[i]=(ft[i-1]<<1)%mm;
126     for(int i=1;i<=n;++i){
127         ans=(ans+ft[f[i]]-1+mm)%mm;
128         ans=(ans-p[i]/2+mm)%mm;
129     }
130     
131     cout<<ans<<endl;
132     return 0;
133 }

 

posted @ 2018-04-29 12:01  ws_zzy  阅读(200)  评论(0编辑  收藏  举报