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

https://www.luogu.com.cn/problem/P3803

参考blog

\(FFT/NTT\)

\(FFT:\)

注意,小数操作运算太慢,不要取\(.0lf\),否则\(TLE\),正确的方法是直接转换为\(int\)(当然要四舍五入)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#define N 10000005
using namespace std;
double Pi=acos(-1.0);
struct virt
{
    double x,y;
    virt operator + (virt b)
    {
        return (virt){x+b.x,y+b.y};
    }
    virt operator - (virt b)
    {
        return (virt){x-b.x,y-b.y};
    }
    virt operator * (virt b)
    {
        return (virt){x*b.x-y*b.y,x*b.y+y*b.x};
    }
}a[N],b[N];
int n,m,q,l,s,r[N];
void FFT(virt *a,double t)
{
    for (int i=0;i<s;i++)
        if (i<r[i])
            swap(a[i],a[r[i]]);
    for (int mid=1;mid<s;mid <<=1)
    {
        virt wn=(virt){cos(Pi/mid),t*sin(Pi/mid)};
        for (int j=0;j<s;j+=(mid << 1))
        {
            virt w=(virt){1.0,0.0};
            for (int k=0;k<mid;k++,w=w*wn)
            {
                virt x=a[j+k],y=w*a[j+k+mid];
                a[j+k]=x+y;
                a[j+k+mid]=x-y;
            }
        }
    }
}
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);
    l=0;
    s=1;
    while (s<=n+m)
    {
        l++;
        s <<=1;
    }
    for (int i=0;i<s;i++)
        r[i]=(r[i >> 1] >> 1)|((i&1) << (l-1));
    FFT(a,1.0);
    FFT(b,1.0);
    for (int i=0;i<=s;i++)
        a[i]=a[i]*b[i];
    FFT(a,-1.0);
    for (int i=0;i<=n+m;i++)
        printf("%d ",(int)(a[i].x/(double)s+0.5));
    putchar('\n');
    return 0;
}

\(NTT:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#define p 998244353
#define G 3
#define N 4000005
#define ll long long
using namespace std;
int Gi;
int n,m,s,l,r[N],a[N],b[N];
inline int ksm(int x,int y)
{
    int ans=1;
    while (y)
    {
        if (y & 1)
            ans=(ll)ans*x%p;
        x=(ll)x*x%p;
        y >>=1;
    }
    return ans;
}
inline void NTT(int *a,int t)
{
    for (int i=0;i<s;i++)
        if (i < r[i])
            swap(a[i],a[r[i]]);
    for (int mid=1;mid<s;mid <<=1)
    {
        int gn=ksm(t,(p-1)/(mid << 1));
        for (int j=0;j<s;j+=(mid << 1))
        {
            int g=1;
            for (int k=0;k<mid;k++,g=(ll)g*gn%p)
            {
                int x=a[j+k],y=(ll)g*a[j+k+mid]%p;
                a[j+k]=(x+y)%p;
                a[j+k+mid]=(x-y)%p;
            }
        }
    }
}
int main()
{
    Gi=ksm(G,p-2);
    scanf("%d%d",&n,&m);
    for (int i=0;i<=n;i++)
        scanf("%d",&a[i]);
    for (int i=0;i<=m;i++)
        scanf("%d",&b[i]);
    s=1,l=0;
    while (s<=n+m)
    {
        s <<=1;
        l++;
    }
    for (int i=0;i<s;i++)
        r[i]=(r[i >> 1] >> 1) | ((i & 1) << (l-1));
    NTT(a,G);
    NTT(b,G);
    for (int i=0;i<s;i++)
        a[i]=(ll)a[i]*b[i]%p;
    NTT(a,Gi);
    int q=ksm(s,p-2);
    for (int i=0;i<=n+m;i++)
    {
        a[i]=(ll)a[i]*q%p;
        a[i]=(a[i]%p+p)%p;
    }
    for (int i=0;i<=n+m;i++)
        printf("%d ",a[i]);
    putchar('\n');
    return 0;
}
posted @ 2020-07-28 11:47  GK0328  阅读(95)  评论(0编辑  收藏  举报