zoukankan      html  css  js  c++  java
  • 快速数论变换(NTT)

    刚学完FFT,干脆把NTT也学了算了

    (一)预备知识

    关于原根,这里说得蛮详细的百度百科

    为什么使用原根呢?为什么原根可以替代(omega_{n})呢?想知道为什么就看here

    NTT用到的各种素数,在这里here

    (二)重要知识

    直接上代码
    原题洛谷P1919

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    typedef long long ll;
    typedef double dd;
    #define For(i,j,k) for (int i=j;i<=k;++i)
    #define Forr(i,j,k) for (int i=j;i>=k;--i)
    #define Set(a,p) memset(a,p,sizeof(a))
    using namespace std;
    
    template<typename T>bool chkmax(T& a,T b) {return a<b?a=b,1:0;}
    template<typename T>bool chkmin(T& a,T b) {return a>b?a=b,1:0;}
    
    const int maxn=200000+100;
    const ll modd=998244353;
    int n,N,cnt;
    int p[maxn];
    ll g,a[maxn],b[maxn];
    char ss[maxn];
    
    ll quick(ll a,ll b) {
        ll s=1;
        while (b) {
            if (b%2) s=s*a%modd;
            a=a*a%modd; b/=2;
        }
        return s;
    }
    
    inline void NTT(ll *s,int type) {
        For (i,0,N-1)
            if (i<p[i]) swap(s[i],s[p[i]]);
        for (int mid=1;mid<N;mid<<=1) {
            int len=mid<<1;
            ll wn=quick(g,type==1?(modd-1)/len:modd-1-(modd-1)/len);
            for (int j=0;j<N;j+=len) {
                ll w=1;
                for (int k=0;k<mid;++k,w=w*wn%modd) {
                    ll t=w*s[j+mid+k]%modd;
                    s[j+mid+k]=(s[j+k]-t+modd)%modd;
                    s[j+k]=(s[j+k]+t)%modd;
                }
            }
        }
        if (type==-1) {
            ll inv=quick(N,modd-2);
            For (i,0,N) s[i]=s[i]*inv%modd;
        }
    }
    
    int main() {
        scanf("%d",&n);
        scanf("%s",ss);
        For (i,0,n-1) a[i]=ss[n-1-i]-'0';
        scanf("%s",ss);
        For (i,0,n-1) b[i]=ss[n-1-i]-'0';
        for (N=1;N<2*n;N<<=1,++cnt) ;
        For (i,0,N-1) p[i]=p[i>>1]>>1 | ((i&1)<<(cnt-1));
        g=3;
        NTT(a,1); NTT(b,1);
        For (i,0,N) a[i]=a[i]*b[i]%modd;
        NTT(a,-1);
        ll x=0;
        For (i,0,N) {
            a[i]+=x; x=a[i]/10; a[i]%=10;
        }
        while (!a[N]) N--;
        Forr (i,N,0) printf("%lld",a[i]);
        return 0;
    }
    

    代码要注意,long long 不可乱用!!!

  • 相关阅读:
    依赖注入方法
    依赖注入
    用spring来控制反转(ioc)
    ioc控制反转笔记
    写模块的流程例子
    淘淘商城笔记1
    二叉树的前序中序后序遍历
    专题2 二叉树(go)
    专题1:二分查找
    python自动化开发-[第三天]-编码,函数,文件操作
  • 原文地址:https://www.cnblogs.com/Wuweizheng/p/8553155.html
Copyright © 2011-2022 走看看