BZOJ3160: 万径人踪灭(FFT,回文自动机)
解题思路:
FFT在处理卷积时可以将自己与自己卷,在某一种字母上标1其他标0,做字符集次就好了。
(回文就是直接对称可以联系偶函数定义理解,根据这个性质就可以将字符串反向实现字符串匹配)。
最后利用容斥回文字符2的次幂-回文串就好了。
回文串计数当然要回文自动机了。
代码:
1 #include<cmath> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 typedef long long lnt; 6 const int maxn=362144; 7 const double PI=acos(-1.0); 8 const lnt mod=(lnt)(1e9+7); 9 struct cp{ 10 double x,y; 11 cp(){}; 12 cp(double a,double b){x=a,y=b;} 13 cp friend operator + (cp a,cp b){return cp(a.x+b.x,a.y+b.y);} 14 cp friend operator - (cp a,cp b){return cp(a.x-b.x,a.y-b.y);} 15 cp friend operator * (cp a,cp b){return cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);} 16 }A[maxn],B[maxn],C[maxn]; 17 struct PAM{ 18 struct pant{ 19 int tranc[2]; 20 int len; 21 int pre; 22 int wgt; 23 }h[maxn]; 24 int siz; 25 int fin; 26 lnt ans; 27 bool mis(char *a,int i,int lsp) 28 { 29 return a[i]!=a[i-h[lsp].len-1]; 30 } 31 void Insert(char *a,int i) 32 { 33 int nwp,lsp,mac; 34 lsp=fin; 35 int c=a[i]-'a'; 36 while(mis(a,i,lsp)) 37 lsp=h[lsp].pre; 38 if(!h[lsp].tranc[c]) 39 { 40 nwp=++siz; 41 mac=h[lsp].pre; 42 h[nwp].len=h[lsp].len+2; 43 while(mis(a,i,mac)) 44 mac=h[mac].pre; 45 h[nwp].pre=h[mac].tranc[c]; 46 h[lsp].tranc[c]=nwp; 47 h[nwp].wgt=h[h[nwp].pre].wgt+1; 48 } 49 fin=h[lsp].tranc[c]; 50 ans+=h[fin].wgt; 51 return ; 52 } 53 PAM(){} 54 PAM(char *a,int n) 55 { 56 ans=0; 57 siz=1; 58 fin=0; 59 h[1].pre=h[0].pre=1; 60 h[1].len=-1; 61 h[0].len=0; 62 for(int i=1;i<=n;i++) 63 Insert(a,i); 64 } 65 lnt val(void) 66 { 67 return ans; 68 } 69 }; 70 int lim; 71 int len; 72 int n,m; 73 int pos[maxn]; 74 lnt pow2[maxn]; 75 char str[maxn]; 76 void getpos(void) 77 { 78 for(int i=0;i<len;i++) 79 pos[i]=(pos[i>>1]>>1)|((i&1)<<(lim-1)); 80 return ; 81 } 82 void Fft(cp *a,double flag) 83 { 84 for(int i=0;i<len;i++) 85 if(i<pos[i]) 86 std::swap(a[i],a[pos[i]]); 87 for(int i=2;i<=len;i<<=1) 88 { 89 cp wn(cos(2.00*PI*flag/(double)(i)),sin(2.00*PI*flag/(double)(i))); 90 for(int j=0;j<len;j+=i) 91 { 92 cp w(1.00,0.00),t; 93 for(int k=0;k<(i>>1);k++,w=w*wn) 94 { 95 t=a[k+j+(i>>1)]*w; 96 a[j+k+(i>>1)]=a[j+k]-t; 97 a[j+k]=a[j+k]+t; 98 } 99 } 100 } 101 return ; 102 } 103 int main() 104 { 105 scanf("%s",str+1); 106 int lth=strlen(str+1); 107 for(int i=1;i<=lth;i++) 108 if(str[i]=='a') 109 A[i-1].x=1.00; 110 else 111 B[i-1].x=1.00; 112 while((1<<lim)<(lth<<1)) 113 lim++; 114 len=1<<lim; 115 getpos(); 116 Fft(A,1); 117 Fft(B,1); 118 for(int i=0;i<len;i++) 119 A[i]=A[i]*A[i]+B[i]*B[i]; 120 Fft(A,-1); 121 pow2[0]=1; 122 for(int i=1;i<=len;i++) 123 pow2[i]=pow2[i-1]*2ll%mod; 124 lnt ans=0; 125 for(int i=0;i<len;i++) 126 ans=(ans+pow2[((lnt)(A[i].x/(double)(len)+0.5)+1ll)/2]-1ll)%mod; 127 PAM P(str,lth); 128 ans=((ans-P.val())%mod+mod)%mod; 129 printf("%lld\n",ans); 130 return 0; 131 }