bzoj 2194: 快速傅立叶之二NTT

Posted lokiii

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 2194: 快速傅立叶之二NTT相关的知识,希望对你有一定的参考价值。

看别的blog好像我用了比较麻烦的方法……
(以下的n都--过
\[ c[i]=\sum_{j=i}^{n}a[i]*b[j-i] \]
设j=i+j
\[ c[i]=\sum_{j=0}^{n-i}a[i+j]*b[i+j-i] \]
\[ c[i]=\sum_{j=0}^{n-i}a[i+j]*b[j] \]
再设j=n-i-j
\[ c[i]=\sum_{n-i-j}^{n-i}a[n-i-j+i]b[n-i-j] \]
\[ n-i-j \geq 0 \Rightarrow j \leq n-i \]
\[ n-i-j<=n-i \Rightarrow j \geq 0 \]
\[ c[i]=\sum_{j=0}^{n-i}a[n-j]b[n-i-j] \]
然后把n-i和i换一下
\[ c[n-i]=\sum_{j=0}^{i}a[n-j]b[i-j] \]
至此,只有a看起来不是卷积,于是可以在读入的时候就把a数组翻转(读入b[i],a[n-i]即可)
然后注意c也是反转的,输出的时候倒着输出

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int mod=998244353,G=3,N=5e6;
int lm,bt,n,re[N],ans[N],a[N],b[N];
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>‘9‘||p<‘0‘)
    {
        if(p==‘-‘)
            f=-1;
        p=getchar();
    }
    while(p>=‘0‘&&p<=‘9‘)
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
int ksm(int a,int b)
{
    int r=1;
    while(b)
    {
        if(b&1)
            r=1ll*r*a%mod;
        a=1ll*a*a%mod;
        b>>=1;
    }
    return r;
}
void dft(int a[],int f)
{
    for(int i=0;i<lm;i++)
        if(i<re[i])
            swap(a[i],a[re[i]]);
    for(int i=1;i<lm;i<<=1)
    {
        int wi=ksm(G,(mod-1)/(i*2));
        if(f==-1)
            wi=ksm(wi,mod-2);
        for(int k=0;k<lm;k+=(i<<1))
        {
            int w=1,x,y;
            for(int j=0;j<i;j++)
            {
                x=a[k+j];
                y=1ll*w*a[k+j+i]%mod;
                a[k+j]=((x+y)%mod+mod)%mod;
                a[k+j+i]=((x-y)%mod+mod)%mod;
                w=1ll*w*wi%mod;
            }
        }
    }
    if(f==-1)
    {
        int inv=ksm(lm,mod-2);
        for(int i=0;i<lm;i++)
            a[i]=1ll*a[i]*inv%mod;
    }
}
void ntt()
{
    bt=1;
    for(;(1<<bt)<=2*n;bt++);
    lm=(1<<bt);
    for(int i=0;i<=lm;i++)
        re[i]=(re[i>>1]>>1)|((i&1)<<(bt-1));
    dft(a,1);
    dft(b,1);
    for(int i=0;i<lm;i++)
        a[i]=1ll*a[i]*b[i]%mod;
    dft(a,-1);
}
int main()
{
    n=read();
    n--;
    for(int i=0;i<=n;i++)
        a[n-i]=read(),b[i]=read();
    ntt();
    for(int i=n;i>=0;i--)
        printf("%d\n",a[i]);
    return 0;
}

以上是关于bzoj 2194: 快速傅立叶之二NTT的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 2194: 快速傅立叶之二NTT

BZOJ 2194: 快速傅立叶之二

BZOJ 2194 快速傅立叶之二 ——FFT

bzoj2194: 快速傅立叶之二

bzoj2194: 快速傅立叶之二

bzoj千题计划256:bzoj2194: 快速傅立叶之二