[bzoj2194]快速傅立叶之二——FFT 大佬们的博客 Some Links

版权声明:欢迎大家转载,转载请标明出处。 https://blog.csdn.net/ylsoi/article/details/81951397

题目大意:

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

思路:

不难发现有贡献的点对在两个数组中的下标差为定值,一个经典的做法是将其中一个数组反转过来,这样之后就变成了和为定值,这刚好满足多项式乘法的系数表示方式,直接FFT即可。

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
typedef long long ll;

using namespace std;

void File(){
    freopen("bzoj2194.in","r",stdin);
    freopen("bzoj2194.out","w",stdout);
}

const double pi=acos(-1.0);
const int maxn=4e5+10;
int n,lim=1,len,dn[maxn],ans[maxn];

struct Complex{
    double x,y;
    Complex(double xx=0,double yy=0){x=xx,y=yy;}
};
Complex operator + (Complex a,Complex b){return (Complex){a.x+b.x,a.y+b.y};}
Complex operator - (Complex a,Complex b){return (Complex){a.x-b.x,a.y-b.y};}
Complex operator * (Complex a,Complex b){return (Complex){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};}
Complex a[maxn],b[maxn];

void fft(Complex *A,int ty){
    REP(i,0,lim-1)if(i<dn[i])swap(A[i],A[dn[i]]);
    for(int mid=1;mid<lim;mid<<=1){
        Complex w(cos(2.0*pi/(mid<<1)),ty*sin(2.0*pi/(mid<<1)));
        for(int L=0;L<lim;L+=mid<<1){
            Complex wk(1,0);
            REP(i,L,L+mid-1){
                Complex u=A[i],v=wk*A[i+mid];
                A[i]=u+v;
                A[i+mid]=u-v;
                wk=wk*w;
            }
        }
    }
}

int main(){
    File();
    scanf("%d",&n);
    int u,v;
    REP(i,1,n){
        scanf("%d%d",&u,&v);
        a[i-1].x=u;
        b[n-i].x=v;
    }
    while(lim<=((n-1)<<1))lim<<=1,++len;
    if(!len)len=1;
    REP(i,0,lim-1)dn[i]=(dn[i>>1]>>1)|((i&1)<<(len-1));
    fft(a,1);
    fft(b,1);
    REP(i,0,lim-1)a[i]=a[i]*b[i];
    fft(a,-1);
    REP(i,0,n-1)ans[i]=(int)(a[n+i-1].x/lim+0.5);
    REP(i,0,n-1)printf("%d\n",ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ylsoi/article/details/81951397