bzoj2194 快速傅里叶之二
题意:对于k = 0 ... n求
解:
首先把i变成从0开始
我们发现a和b的次数(下标)是成正比例的,这不可,于是反转就行了。
反转b的话,会发现次数和是n + k,这不可。
反转a就很吼了。
这个东西恰好是卷积出来的第n - k项的系数。
所以我们把a串反转,然后用a与b卷积,最后再反转输出即可。
1 /************************************************************** 2 Problem: 2194 3 Language: C++ 4 Result: Accepted 5 Time:133643896 ms 6 Memory:14342474884 kb 7 ****************************************************************/ 8 9 #include <cstdio> 10 #include <algorithm> 11 #include <cmath> 12 #include <cstring> 13 14 const int N = 100010; 15 const double pi = 3.1415926535897932384626; 16 17 struct cp { 18 double x, y; 19 cp(double X = 0, double Y = 0) { 20 x = X; 21 y = Y; 22 } 23 inline cp operator +(const cp &w) const { 24 return cp(x + w.x, y + w.y); 25 } 26 inline cp operator -(const cp &w) const { 27 return cp(x - w.x, y - w.y); 28 } 29 inline cp operator *(const cp &w) const { 30 return cp(x * w.x - y * w.y, x * w.y + y * w.x); 31 } 32 }a[N << 2], b[N << 2]; 33 34 int r[N << 2]; 35 36 inline void FFT(int n, cp *a, int f) { 37 for(int i = 0; i < n; i++) { 38 if(i < r[i]) { 39 std::swap(a[i], a[r[i]]); 40 } 41 } 42 43 for(int len = 1; len < n; len <<= 1) { 44 cp Wn(cos(pi / len), f * sin(pi / len)); 45 for(int i = 0; i < n; i += (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; 50 a[i + j] = a[i + j] + t; 51 w = w * Wn; 52 } 53 } 54 } 55 56 if(f == -1) { 57 for(int i = 0; i <= n; i++) { 58 a[i].x /= n; 59 } 60 } 61 return; 62 } 63 64 int main() { 65 int n; 66 scanf("%d", &n); 67 n--; 68 for(int i = 0; i <= n; i++) { 69 scanf("%lf%lf", &a[n - i].x, &b[i].x); 70 } 71 72 int len = 2, lm = 1; 73 while(len <= (n << 1)) { 74 len <<= 1; 75 lm++; 76 } 77 for(int i = 1; i <= len; i++) { 78 r[i] = (r[i >> 1] >> 1) | ((i & 1) << (lm - 1)); 79 } 80 81 FFT(len, a, 1); 82 FFT(len, b, 1); 83 for(int i = 0; i <= len; i++) { 84 a[i] = a[i] * b[i]; 85 } 86 FFT(len, a, -1); 87 88 for(int i = 0; i <= n; i++) { 89 printf("%d\n", (int)(a[n - i].x + 0.5)); 90 } 91 92 return 0; 93 }