如何学习这些毒瘤?
背模板!......反正学了不久就忘光了,还是背模板来的实在。
1.FFT
快速傅里叶变换。一切的基础。
作用是在 点值式 与 系数式 之间进行转换。
首先我们要手写复数。
然后背下来这个预处理的东西:
r[i] = (r[i >> 1] >> 1) | ((i & 1) << (lm - 1));
把n补全为2的次幂,下界为 n + m + 1,数组开4倍以上。
然后注意把n补全之后的各个地方n的写法:
FFT中都是 < n,涉及要实际输出的是 <= n
最后别忘了 / n,输出时 + 0.5,输出 [0, n + m]
中间也要记清楚,Wn = (cos(pi / len), f * sin(pi / len));
手写pi的精度高一些,3.1415926 5358979 32384626
FFT前记得置换。
上代码:
1 #include <cstdio> 2 #include <algorithm> 3 #include <cmath> 4 const int N = 1000010; 5 const double pi = 3.1415926535897932384626; 6 7 struct cp { 8 double x, y; 9 cp(double tx = 0.0, double ty = 0.0) { 10 this->x = tx; 11 this->y = ty; 12 } 13 inline cp operator +(const cp &d) const { 14 return cp(x + d.x, y + d.y); 15 } 16 inline cp operator -(const cp &d) const { 17 return cp(x - d.x, y - d.y); 18 } 19 inline cp operator *(const cp &d) const { // 复数的乘法直接代数展开就能得到公式 20 return cp(x * d.x - y * d.y, x * d.y + y * d.x); 21 } 22 }A[N << 2], B[N << 2]; // 空间开单个多项式的4倍 23 24 int r[N << 2], n, lm; 25 26 inline void init() { 27 while((1 << lm) < n) { 28 lm++; 29 } 30 n = 1 << lm; 31 for(int i = 1; i < n; i++) { // 这里从 0 或 1 开始,到 n 或 n - 1 都行 32 r[i] = (r[i >> 1] >> 1) | ((i & 1) << (lm - 1)); // 背诵! 33 } 34 return; 35 } 36 37 inline void FFT(int n, cp *a, int f) { 38 for(int i = 0; i < n; i++) { 39 if(i < r[i]) { 40 std::swap(a[i], a[r[i]]); // 先转换 41 } 42 } 43 for(int len = 1; len < n; len = len << 1) { // len 是倍增的 44 cp Wn(cos(pi / len), f * sin(pi / len)); // 背诵! 45 for(int i = 0; i < n; i += (len << 1)) { // 加的是 (len << 1) ! 46 cp w(1, 0); // 这里三个 < 没有 <= 47 for(int j = 0; j < len; j++) { 48 cp t = a[i + len + j] * w; 49 a[i + len + j] = a[i + j] - t; /// error : t -> w 50 a[i + j] = a[i + j] + t; 51 w = w * Wn; 52 } 53 } 54 } 55 if(f == -1) { 56 for(int i = 0; i <= n; i++) { 57 a[i].x /= n; // 除n 58 } 59 } 60 return; 61 } 62 63 int main() { 64 int n1, n2; 65 scanf("%d%d", &n1, &n2); 66 for(int i = 0; i <= n1; i++) { 67 scanf("%lf", &A[i].x); 68 } 69 for(int i = 0; i <= n2; i++) { 70 scanf("%lf", &B[i].x); 71 } 72 73 n = n1 + n2 + 1; 74 init(); 75 76 FFT(n, A, 1); 77 FFT(n, B, 1); 78 for(int i = 0; i <= n; i++) { 79 A[i] = A[i] * B[i]; 80 } 81 FFT(n, A, -1); 82 83 for(int i = 0; i <= n1 + n2; i++) { 84 printf("%d ", (int)(A[i].x + 0.5)); 85 } 86 87 return 0; 88 }