【BZOJ 2194】 快速傅立叶之二

来源:互联网 发布:旋律合成软件app 编辑:程序博客网 时间:2024/05/21 10:37

思路:

这个题引入了卷积的知识,下面的式子是一种常用的卷积:

F(x)=fg=i=0xf(i)g(xi)

形象的理解:

如果0n的对应位相乘,所得到的项的位置坐标和相等,这就等价于多项式当中的一个x的幂,累加起来的是x的系数。
那么就模拟多项式的过程,如果RFFT的答案数组,那F(x)=R[x]
不难发现,卷积的后两个系数相加,就是现在的答案在FFT答案数组中的位置。

再看这个题:

C[k]=i=kn1a[i]b[ik]

可是这不是卷积的形式,我们可以先把所有的i缩小k

C[k]=i=0nk1a[i+k]b[i]

为了凑成卷积的形式,我们把a前后翻转,变为ra,所以:

C[k]=i=0nk1ra[nk1i]b[i]

然后就化成了卷积的形式,但是对于一个k的答案,他在FFT中算出来的数要相反,所以C[k]=R[nk1]

代码:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>using namespace std;const int maxn = 100010*3;const double pi = acos(-1);int Bit, rx[maxn];struct Com{    double x, y;    Com(double X = 0, double Y = 0){x = X, y = Y;}    Com(const Com &t){x = t.x, y = t.y;}    Com operator + (const Com &t) const{return Com(x+t.x, y+t.y);}    Com operator - (const Com &t) const{return Com(x-t.x, y-t.y);}    Com operator * (const Com &t) const{return Com(x*t.x-y*t.y, x*t.y+t.x*y);}};void fft(Com *A, int n, int f){    if(rx[n-1] != n-1) for(int i = 0; i < n; i ++) rx[i] = (rx[i>>1]>>1) | ((i&1)<<(Bit-1));    for(int i = 0; i < n; i ++) if(i < rx[i]) swap(A[i], A[rx[i]]);    for(int i = 1; i < n; i <<= 1){        const Com Base(cos(pi/i), f*sin(pi/i));        for(int j = 0; j < n; j += (i<<1)){            Com mi(1, 0);            for(int k = 0; k < i; k ++, mi = mi * Base){                Com x = A[j+k], y = A[i+j+k] * mi;                A[j+k] = x+y, A[i+j+k] = x-y;            }        }    }}int n, m;Com a[maxn], b[maxn];int main(){    scanf("%d", &n), m = -- n;    for(int i = 0; i <= n; i ++) scanf("%lf%lf", &a[n-i].x, &b[i].x);    m += n;    for(n = 1; n <= m; n <<= 1, Bit ++);    fft(a, n, 1), fft(b, n, 1);    for(int i = 0; i < n; i ++) a[i] = a[i] * b[i];    fft(a, n, -1);    for(int i = m/2; i >= 0; i --) printf("%d\n", int((a[i].x/n)+0.5));    return 0;}
0 0
原创粉丝点击