bzoj 2194: 快速傅立叶之二 fft

Description

请计算C[k]=sigma(a[i]*b[i-k]) 其中 k < = i < n ,并且有 n < = 10 ^ 5。 a,b中的元素均为小于等于100的非负整数。

Input

第一行一个整数N,接下来N行,第i+2..i+N-1行,每行两个数,依次表示a[i],b[i] (0 < = i < N)。
Output

输出N行,每行一个整数,第i行输出C[i-1]。

Sample Input

5

3 1

2 4

1 1

2 4

1 4
Sample Output

24

12

10

6

1

分析:萌新又来刷水题啦。fft的板子题。我居然把单位复根的cos和sin打反了,怕不是数学白学了。

代码:

/**************************************************************
    Problem: 2194
    User: beginend
    Language: C++
    Result: Accepted
    Time:2848 ms
    Memory:15352 kb
****************************************************************/

#include <iostream>
#include <cstdio>
#include <cmath>

const int maxn=4e5+7;
const double pi=acos(-1);

struct rec{
    double x,y;
};

rec operator +(rec x,rec y)
{
    return (rec){x.x+y.x,x.y+y.y};
}

rec operator -(rec x,rec y)
{
    return (rec){x.x-y.x,x.y-y.y};
}

rec operator *(rec x,rec y)
{
    return (rec){x.x*y.x-x.y*y.y,x.y*y.x+x.x*y.y};
}

using namespace std;

rec a[maxn],b[maxn];
int r[maxn];
int n,l,lg;

void fft(rec *a,int f)
{
    for (int i=0;i<l;i++)
    {
        if (r[i]>i) swap(a[i],a[r[i]]);
    }
    for (int i=2;i<=l;i*=2)
    {
        rec wn=(rec){cos(2*pi/i),f*sin(2*pi/i)};
        for (int j=0;j<l;j+=i)
        {
            rec w=(rec){1,0};
            for (int k=0;k<i/2;k++)
            {
                rec u=a[j+k],v=w*a[j+k+i/2];
                a[j+k]=u+v;
                a[j+k+i/2]=u-v;
                w=w*wn;
            }
        }
    }
}

int main()
{
    scanf("%d",&n);
    for (int i=0;i<n;i++)
    {
        scanf("%lf%lf",&a[n-i-1].x,&b[i].x);
    }
    l=1;lg=0;
    while (l<=(n*2)) l*=2,lg++;
    for (int i=0;i<l;i++) r[i]=((r[i>>1]>>1)|((i&1)<<(lg-1))); 
    fft(a,1);
    fft(b,1);
    for (int i=0;i<l;i++)
    {
        a[i]=a[i]*b[i];
    }   
    fft(a,-1);
    for (int i=n-1;i>=0;i--) printf("%.0lf\n",a[i].x/l+0.01);
}


猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/80218140