• 快速数论变换NTT


    单位根

      多项式 $x^n=1$ 的根称为 n 次单位根。

      设 $omega_{n}=e^{ipi}$为复数,

      由欧拉公式$e^{ix}=cosx+isinx$

      容易验证$omega_{n}^{n}=1$;

      

      考虑膜意义下的单位根  $x^{n}equiv 1(mod p)$

      对于质数 $p=kn+1$,设 为$mathbb{F}_{p}$中的元素,其中$g$为模$p$的原根,那么显然$omega_{n}^{n}=1$。 

    原根

    原根,是一个数学符号。设$p$是正整数,$g$是整数,若$g$模$p$的阶等于$φ(p)$,则称$g$为模$p$的一个原根。

      那么对质数$p$而言,$phi(p)=p-1$

    设$a$,$p$是整数,$a$和$p$互素,那么:

    使$a^{n}equiv 1(mod p)$

    成立的最小正整数$n$叫做$a$膜$p$的阶

      在上述两种情况下,1,$omega_{n}^{1}$,$omega_{n}^{2}$...$omega_{n}^{n-1}$为$n$个不同的$n$次单位根

      $FTT$与$NTT$只在单位根定义上有些许差异,其他都大同小异

      由于要快速变换,所以要求$p=k*2^{l}+1$

      这样的话原根$g^{k*2^{l}}equiv 1(mod p)$,

      而如果$g^{k*2^{l}}$不是2的整数倍的话,在分治迭代过程中会出现分数指数,即会出现根号。

      这样可以处理$limleq 2^{l}$的多项式

      推荐模数:

    模数 $k$ $l$ $g$
    $998244353$ $7$$*$$17$ $23$ $3$

      

      注意:$2^{23}<10^{6}$

    code:

      

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=1<<22;
    const int P=998244353;
    const ll g=3;
    const ll invg=332748118;
    ll r[N],lim,L,n,m;
    ll a[N],b[N];
    ll ksm(ll x,ll n) {
        ll ans=1;
        while(n){
            if(n&1)ans=(ans*x)%P;
            n>>=1;
            x=(x*x)%P;
        }
        return ans;
    }
    void ntt(ll *f,int op){
        for(int i=0;i<lim;i++){
            if(i<r[i]){
                swap(f[i],f[r[i]]);
            }
        }
        for(int p=2;p<=lim;p<<=1){
            int len=p>>1;
            ll Wn=ksm(op==1?g:invg,(P-1)/p);
            for(int j=0;j<lim;j+=p){
                ll w=1;
                for(int k=j;k<j+len;k++){
                    ll t=w*f[k+len]%P;
                    f[k+len]=(f[k]-t+P)%P;
                    f[k]=(f[k]+t)%P;
                    w=(w*Wn)%P;
                }
            }
        }
    }
    int main(){
        cin>>n>>m;
        for(int i=0;i<=n;i++){
            scanf("%d",&a[i]);
            a[i]=(a[i]+P)%P;
        }
        for(int i=0;i<=m;i++){
            scanf("%d",&b[i]);
            b[i]=(b[i]+P)%P;
        }
        while(1<<L<=n+m)L+=1;
        lim=1<<L;
        for(int i=0;i<lim;i++){
            r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
        }
        ntt(a,1);
        ntt(b,1);
        for(int i=0;i<lim;i++){
            a[i]=a[i]*b[i]%P;
        }
        ntt(a,-1);
        ll inv=ksm(lim,P-2);
        for(int i=0;i<=n+m;i++){
            printf("%lld ",(a[i]*inv)%P);
        }
        puts("");
        return 0;
    }

     

  • 相关阅读:
    Spring Cloud Stream
    解决eclipse中git插件中的cannot open git-upload-pack问题
    Unsupported major.minor version 51.0解决办法
    git将本地仓库上传到远程仓库
    Ubuntu下如何安装与运行Redis
    git中进入带有空格的目录下的解决办法
    http://www.111cn.net/jsp/Jsp-Servlet/45158.htm
    MySQL 5.6 for Windows 解压缩版配置安装
    http://blog.csdn.net/congcong68/article/details/39252897
    http://jingyan.baidu.com/article/bad08e1ee14ae409c85121cf.html
  • 原文地址:https://www.cnblogs.com/Hikigaya/p/11246543.html
Copyright © 2020-2023  润新知