luoguP3803 【模板】多项式乘法(FFT)

题目大意:给出两个系数表达式,求卷积。

这是一道fft板子题。讲一下fft为什么叫(fast_fast_tle)

正常的系数相乘的时间复杂度为O(n^2),应该不需要证明。

但是某位神犇想出了一个强大的套路:

1.系数表达式->点值表达式;(O(nlogn))

2.点值相乘;(O(n))

3.点值表达式->系数表达式;(O(nlogn))

这样就成O(nlogn)了!

然而前提是fft与单位复数根的结合。

代码:

#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
#define N 10000500
int n,m,len=1;
struct cp
{
    double x,y;
    cp(){}
    cp(double x,double y):x(x),y(y){}
}a[N<<1],b[N<<1];
cp operator + (cp a,cp b)
{
    return cp(a.x+b.x,a.y+b.y);
}
cp operator - (cp a,cp b)
{
    return cp(a.x-b.x,a.y-b.y);
}
cp operator * (cp a,cp b)
{
    return cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);
}
int l,r[N<<1],ans[N<<1];
const double Pi = acos(-1.0);
void fft(cp *c,int k)
{
    for(int i=0;i<len;i++)
        if(i<r[i])swap(c[i],c[r[i]]);
    for(int i=1;i<len;i<<=1)
    {
        cp w0(cos(Pi/i),k*sin(Pi/i));
        for(int j=0;j<len;j+=(i<<1))
        {
            cp w(1,0);
            for(int r=0;r<i;r++,w=w*w0)
            {
                cp x = c[j+r],y = w*c[j+r+i];
                c[j+r] = x+y;c[j+r+i]=x-y;
            }
        }
    }
}
void conv()
{
    fft(a,1);fft(b,1);
    for(int i=0;i<=len;i++)a[i]=a[i]*b[i];
    fft(a,-1);
    for(int i=0;i<=n+m;i++)ans[i]=(int)(a[i].x/len+0.5);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<=n;i++)scanf("%lf",&a[i].x);
    for(int i=0;i<=m;i++)scanf("%lf",&b[i].x);
    while(len<=n+m)len<<=1,l++;//<=
    for(int i=0;i<len;i++)
        r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    conv();
    for(int i=0;i<=n+m;i++)printf("%d ",ans[i]);
    printf("\n");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/LiGuanlin1124/p/9695924.html
今日推荐