1. 程式人生 > >bzoj 3160 萬徑人蹤滅——FFT

bzoj 3160 萬徑人蹤滅——FFT

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=3160

似乎理解加深了。

用卷積算相同的位置;先把 a 賦成1、 b 賦成0,卷積一遍;再把 a 賦成0、 b 賦成1,卷積一遍;兩個加起來就有了每個位置的值,它表示以該位置/2(/2的位置可以是裂縫)為對稱軸的迴文位置個數。

然後用馬拉車把連續區間的情況去掉。

注意一下單個元素也要算上,因為有那種奇數的;馬拉車裡別忘了把單個元素減去。

因為FFT的兩個陣列是一樣的,所以FFT一次,然後自己乘自己就行了。

雖然調了很久但其實也沒什麼要注意的。

#include<iostream>
#include
<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define ll long long #define db double using namespace std; const int N=1e5+5,M=N<<2,mod=1e9+7; const db pi=acos(-1); int n,r[M],len,ans,bin[N]; char ch[N],tc[N<<1]; struct cpl{db x,y;}a[M],b[M],I; cpl
operator+ (cpl a,cpl b){return (cpl){a.x+b.x,a.y+b.y};} cpl operator- (cpl a,cpl b){return (cpl){a.x-b.x,a.y-b.y};} cpl operator* (cpl a,cpl b){return (cpl){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};} void upd(int &x){x>=mod?x-=mod:0;x<0?x+=mod:0;} void fft(cpl *a,bool fx) { for(int i=0;i<len;i++)
if(i<r[i])swap(a[i],a[r[i]]); for(int R=2;R<=len;R<<=1)//<<=1 { int m=R>>1; cpl Wn=(cpl){ cos(pi/m),fx?-sin(pi/m):sin(pi/m) }; for(int i=0;i<len;i+=R) { cpl w=I; for(int j=0;j<m;j++,w=w*Wn)//w=w*Wn { cpl tmp=w*a[i+m+j]; a[i+m+j]=a[i+j]-tmp; a[i+j]=a[i+j]+tmp; } } } } void manachar() { int m=(n<<1)-1; for(int i=0,j=0;j<n;i+=2,j++) tc[i]=ch[j],tc[i+1]=','; int id=0; r[0]=0;ans--; for(int i=1;i<m;i++) { r[i]=0; if(id+r[id]>i) { r[i]=min(id+r[id]-i,r[(id<<1)-i]); } if(id+r[id]<=i+r[i]) { for(;i+r[i]<m&&i-r[i]>=0&&tc[i+r[i]]==tc[i-r[i]];r[i]++); r[i]--; id=i; } int tmp=(r[i]+(tc[i]==','))>>1;//don't change r[i]!!!!!! ans-=tmp+(tc[i]!=','); upd(ans); } } int main() { I.x=1; scanf("%s",ch);n=strlen(ch); bin[0]=1; for(int i=1,m=n+1>>1;i<=m;i++)bin[i]=bin[i-1]<<1,upd(bin[i]); len=1; for(;len<=n<<1;len<<=1); for(int i=0;i<len;i++) r[i]=(r[i>>1]>>1)+((i&1)?len>>1:0); for(int i=0;i<n;i++) if(ch[i]=='a')a[i].x=1; fft(a,0); for(int i=0;i<len;i++)a[i]=a[i]*a[i]; fft(a,1); for(int i=0;i<n;i++) if(ch[i]=='b')b[i].x=1; fft(b,0); for(int i=0;i<len;i++)b[i]=b[i]*b[i]; fft(b,1); for(int i=0;i<len;i++)//len { a[i].x=(int(a[i].x/len+0.5)+1)>>1; b[i].x=(int(b[i].x/len+0.5)+1)>>1; a[i].x+=b[i].x; ans+=bin[(int)a[i].x]-1; upd(ans); } manachar(); printf("%d\n",ans); return 0; }