【BZOJ 2194】 快速傅立叶之二

2194: 快速傅立叶之二

Time Limit: 10 Sec Memory Limit: 259 MB
Submit: 430 Solved: 240
[Submit][Status][Discuss]
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模板题。

FFT思想详见【BZOJ 2179】

FFT是计算下标为定值的两个多项式乘积的,而本题差是定值,我们只要把a[]数组逆序,就变成和为定值了!

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <complex>
#define N 500005
#define pi acos(-1)
#define LL long long
using namespace std;
int n;
complex<double> a[N],b[N],p[N];
void read(int &tmp)
{
    tmp=0;
    char ch=getchar();
    int fu=1;
    for (;ch<'0'||ch>'9';ch=getchar())
        if (ch=='-') fu=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())
        tmp=tmp*10+ch-'0';
    tmp*=fu;
}
void FFT(complex<double> x[],int n,int p)
{
    for (int i=0,t=0;i<n;i++)
    {
        if (i>t) swap(x[i],x[t]);
        for (int j=n>>1;(t^=j)<j;j>>=1);
    }
    for (int m=2;m<=n;m<<=1)
    {
        complex<double> wn(cos(p*2*pi/m),sin(p*2*pi/m));
        for (int i=0;i<n;i+=m)
        {
            complex<double> w(1,0),u;
            int k=m>>1;
            for (int j=0;j<k;j++,w*=wn)
            {
                u=x[i+j+k]*w;
                x[i+j+k]=x[i+j]-u;
                x[i+j]=x[i+j]+u;
            }
        }
    }
}
int main()
{
    scanf("%d",&n);
    for (int i=0;i<n;i++)
    {
        int x;
        read(x);
        a[n-i-1]=x;
        read(x);
        b[i]=x;
    }
    int nn=n;
    for (int j=n,i=1;(i>>1)<j;i<<=1)
        n=i;
    cout<<n<<endl;
    FFT(a,n,1),FFT(b,n,1);
    for (int i=0;i<n;i++)
        p[i]=a[i]*b[i];
    FFT(p,n,-1);
    for (int i=nn-1;i>=0;i--)
        printf("%lld\n",(LL)(p[i].real()/n+0.5));
    return 0;
}

这里写图片描述

你可能感兴趣的:(fft,OI,bzoj)