bzoj3160 万径人踪灭

 

正解:$FFT+manacher$。

这题写得蛋疼。。主要是$manacher$有一个地方写错调了好久。。还有我的计数方法好像跟网上的有点不一样,感觉自己在搞容斥原理一样。。

我们考虑设$f[i]$为i两边对称的字符对数。例如,$s=aabba$,则$f[3]=1$(下标从1开始)。然后我们发现这个其实很好算。如果$s[i]==s[j]$,那么它必然会对$f[(i+j)/2]$产生贡献。于是我们可以发现,$f[i]=\sum_{x+y=i*2}[s[x]==s[y]]$。然后这个肯定是可以用$FFT$跑的,我们对于$a$跑一次$FFT$,对于$b$再跑一次$FFT$。注意整个方案数会多算一次,$i+i=2*i$的情况也会算一次。最终答案就是$Ans=\sum_{i=1}^{n}2^{f[i]}-1$,然后再减去连续的子序列。连续的子序列我们用一遍$manacher$算出来就行了,然后又是一波容斥。。

 

 1 //It is made by wfj_2048~
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <complex>
 5 #include <cstring>
 6 #include <cstdlib>
 7 #include <cstdio>
 8 #include <vector>
 9 #include <cmath>
10 #include <queue>
11 #include <stack>
12 #include <map>
13 #include <set>
14 #define rhl (1000000007)
15 #define NN (1000010)
16 #define inf (1<<30)
17 #define pi acos(-1)
18 #define il inline
19 #define RG register
20 #define ll long long
21 #define C complex <double>
22 
23 using namespace std;
24 
25 int p[NN],f[NN],bin[NN],rev[NN],n,nn,N,lg;
26 char s[NN],c[NN];
27 C a[NN],b[NN];
28 ll ans,res;
29 
30 il int gi(){
31     RG int x=0,q=1; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
32     if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x;
33 }
34 
35 il ll manacher(){
36     RG int id=1,mx=1; RG ll ans=0; p[1]=1;
37     for (RG int i=2;i<nn;++i){
38     if (i<mx) p[i]=min(p[(id<<1)-i],mx-i); else p[i]=1;
39     while (i-p[i]>=0 && s[i+p[i]]==s[i-p[i]]) p[i]++;
40     if (mx<i+p[i]) mx=i+p[i],id=i;
41     ans+=(p[i]>>1); if (s[i]!='#') ans--;
42     }
43     return ans%rhl;
44 }
45 
46 il void fft(C *a,RG int n,RG int f){
47     for (RG int i=0;i<n;++i) if (i<rev[i]) swap(a[i],a[rev[i]]);
48     for (RG int i=1;i<n;i<<=1){
49     C wn(cos(pi/i),sin(f*pi/i)),x,y;
50     for (RG int j=0;j<n;j+=(i<<1)){
51         C w(1,0);
52         for (RG int k=0;k<i;++k,w*=wn){
53         x=a[j+k],y=w*a[j+k+i];
54         a[j+k]=x+y,a[j+k+i]=x-y;
55         }
56     }
57     }
58     return;
59 }
60 
61 il void work(){
62     scanf("%s",c+1),n=strlen(c+1); s[0]='#';
63     for (RG int i=1;i<=n;++i) s[i<<1]='#',s[(i<<1)-1]=c[i];
64     nn=(n<<1)+1,s[nn]='&'; for (N=1;N<=(nn<<1);N<<=1) lg++;
65     for (RG int i=0;i<=N;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1));
66     for (RG int i=0;i<N;++i) a[i]=s[i]=='a'; fft(a,N,1);
67     for (RG int i=0;i<N;++i) b[i]=a[i]*a[i],a[i]=s[i]=='b';
68     fft(a,N,1); for (RG int i=0;i<N;++i) b[i]+=a[i]*a[i]; fft(b,N,-1);
69     bin[0]=1; for (RG int i=1;i<=nn;++i){ bin[i]=bin[i-1]<<1; if (bin[i]>=rhl) bin[i]-=rhl; }
70     for (RG int i=1;i<nn;++i){
71     f[i]=((int)(b[i<<1].real()/N+0.5)-(s[i]!='#'))>>1;
72     res=bin[f[i]]-1; if (s[i]!='#') ans+=2*res; else ans+=res;
73     if (ans>=rhl) ans-=rhl;
74     }
75     printf("%lld\n",(ans-manacher()+rhl)%rhl); return;
76 }
77 
78 int main(){
79     work();
80     return 0;
81 }

 

posted @ 2017-03-18 11:36  wfj_2048  阅读(175)  评论(0编辑  收藏  举报