bzoj2179【FFT快速傅立叶】
题意:http://www.lydsy.com/JudgeOnline/problem.php?id=2179
sol :FFT,感觉有篇博客写的不错:https://www.zybuluo.com/397915842/note/37965
给你两个多项式or大整数,求乘积
考虑要想确定一个n阶多项式∑ai*(x^i),需要n+1个点
设多项式A,B,将其分别拆成2n+1个点(ai.x,ai.y),(bi.x,bi.y),则其乘积为(ai.x*bi.x,ai.y*bi.y)所对应的多项式
而FFT是用于加速函数式和点值式的相互转化的,这里仅讨论函数式→点值式的转化
考虑将x赋值为e^0 ~ e^(n-1),e=cos(π*i/n)+sin(π*i/n)*sqrt(-1),这样即可使向量构成一个圆,且满足e^n=e^0
对于原式∑ai*(x^i),考虑分治,将其按i的奇偶分成两块,即∑ai*xi(i为奇数)+∑aj*xj(j为偶数)
考虑解决左半边,将x提出后可化为x*∑a(2i+1)*x^(2i),这里我们发现虽然i减半了,但是x的次数并没有变
考虑将x赋值为e^k,则原式可化为x*∑a(2i+1)*e^(2ik),即x*∑a(2i+1)*(e^2k)^i
那么当k<n/2时原式可看做x*∑a(2i+1)*x^i,而当k>n/2时设t=k-n/2,则e^2k=e^2t,令k=t即可回到k<n/2的问题
于是我们便可以递归解决该问题了,P.S.为方便实现,我们可以将n补成2的整数次幂
对于点值式→函数式的变换,再做一遍FFT即可,不过e的纵坐标要取负,ai’=n*ai
P.S.蝴蝶变换可以将代码变成非递归的,优化常数:http://www.cnblogs.com/zpfbuaa/p/5081155.html
代码抄黄学长的OTZ......
#include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<complex> #define pi 3.141592653589 using namespace std; const int Mx=200010; typedef complex <double> C; int n,m,l,r[Mx],c[Mx]; char s[Mx],t[Mx]; C A[Mx],B[Mx]; void fft(C *A,int tag) { for(int i=0;i<n;i++) if(r[i]>i) swap(A[i],A[r[i]]); for(int i=1;i<n;i<<=1) { C e(cos(pi/i),tag*sin(pi/i)); for(int j=0;j<n;j+=i<<1) { C ei=1; for(int k=0;k<i;k++,ei*=e) { C x=A[j+k],y=ei*A[j+k+i]; A[j+k]=x+y,A[j+k+i]=x-y; } } } } int main() { scanf("%d%s%s",&m,s,t); for(int i=0;i<m;i++) A[i]=s[m-i-1]-'0',B[i]=t[m-i-1]-'0'; for(n=1,m<<=1;n<m;n<<=1) l++; for(int i=0;i<n;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));//蝴蝶 fft(A,1),fft(B,1); for(int i=0;i<n;i++) A[i]*=B[i]; fft(A,-1); for(int i=0;i<n;i++) A[i]/=n; for(int i=0;i<m;i++) c[i]=(int) (A[i].real()+0.1); for(int i=0;i<m;i++) if(c[i]>=10) c[i+1]+=c[i]/10,c[i]%=10; else if(!c[i]&&i==m-1) m--; for(int i=m-1;i>=0;i--) printf("%d",c[i]); return 0; }

浙公网安备 33010602011771号