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; }