FFT学习参考这两篇博客,很详细,结合这看,互补。
很大一部分题目需要构造多项式相乘来进行计数问题。
把A和B分别当作多项式的系数。
#include <cstdio> #include <algorithm> #include <cmath> #include <cstring> using namespace std; const double PI = acos(-1.0); const int maxn = 5e4+50; struct Complex { double real,image; ///实部和虚部 Complex(double _real,double _image) { real = _real; image = _image; } Complex(){} }; Complex operator + (const Complex &c1,const Complex &c2) { return Complex(c1.real+c2.real,c1.image+c2.image); } Complex operator - (const Complex &c1,const Complex &c2) { return Complex(c1.real-c2.real,c1.image-c2.image); } Complex operator * (const Complex &c1,const Complex &c2) { return Complex(c1.real*c2.real-c1.image*c2.image, c1.real*c2.image + c1.image * c2.real); } int rev(int id,int len) { int ret = 0; for(int i=0;(1<<i)<len;i++) { ret <<= 1; if(id & (1<<i)) ret |= 1; } return ret; } Complex A[135000]; void FFT(Complex* a,int len,int DFT) ///对a进行DFT或者逆DFT,结果存在a当中 { for(int i = 0; i < len; i++) A[rev(i,len)] = a[i]; ///按其在叶子节点中的顺序存储 for(int s = 1; (1 << s)<= len; s++) { int m = (1 << s); Complex wm = Complex(cos(DFT*2*PI/m),sin(DFT*2*PI/m)); ///主n次单位根 for(int k = 0; k < len; k += m) { Complex w = Complex(1, 0); ///旋转因子 for(int j = 0; j < (m >> 1); j++) { Complex t = w * A[k + j + (m >> 1)]; Complex u = A[k + j]; A[k + j] = u + t; A[k + j + (m >> 1)] = u - t; w = w * wm; } } } if(DFT == -1) for(int i = 0; i < len; i++) A[i].real /= len, A[i].image /= len; for(int i = 0; i < len; i++) a[i] = A[i]; return; } char coA[maxn],coB[maxn]; ///把每一位作为系数 ///乘积后次数最大为2 * n - 2,转换成2的k次幂,(1<<16)<2*n-2<(1<<17) Complex a[135000],b[135000]; int ans[135000]; int main() { while(scanf("%s",coA)!=EOF) { int lenA = strlen(coA); int mia = 0; while((1<<mia)<lenA) mia++; ///2^mia>=lenA scanf("%s",coB); int lenB = strlen(coB); int mib = 0; while((1<<mib)<lenB) mib++; int len(1<<(max(mia,mib)+1)); for(int i=0;i<len;i++) { if(i<lenA) a[i] = Complex(coA[lenA-i-1]-'0',0); ///表示系数,A数组从左往右存了进去 2000 --> 0002 else a[i] = Complex(0,0); if(i<lenB) b[i] = Complex(coB[lenB-i-1]-'0',0); else b[i] = Complex(0,0); } ///求A和B的点值表达式 FFT(a, len, 1); FFT(b, len, 1); for(int i = 0; i < len; i++) a[i] = a[i] * b[i]; ///求C的点值 FFT(a, len, -1); ///逆DFT得到系数 for(int i = 0; i < len; i++) ans[i] = (int)(a[i].real + 0.5); ///四舍五入 for(int i = 0; i <len - 1; i++) { ans[i + 1] += ans[i] / 10; ans[i] %= 10; } bool flag = 0; for(int i = len - 1; i >= 0; i--) ///防止出现前导0 { if(ans[i]) printf("%d",ans[i]), flag = 1; else if(flag || i == 0) printf("0"); } puts(""); } return 0; }