NTT笔记

更好的阅读体验

NTT 笔记

前言:
这个算法是与FFT 类似的,本篇不会再从头讲起,建议先去补补课《FFT 笔记》
本文只会讲一下互相关联的地方与一些不同的地方。

建议:在电脑前放好演算纸和笔。

注:本篇文章是我这个小蒟弱写的,真正的dalao请看个玩笑便好,不必争论对错(但是欢迎指出文章存在的小错误)。

NTT 有什么用

与FFT 一样,快速数论变换(NTT)可以在 O ( n log ⁡ n ) O(n\log n) O(nlogn)完成两个多项式相乘问题。

为什么要用 NTT

在一些 O ( n 2 ) O(n^2) O(n2)会爆,但是数据很大有需要一个数的时候,显然FFT就不太适用了,就需要用到NTT。

下面补充了一些数论知识,以便你能看懂下文。

补充芝士
1.剩余系:所有整数模正整数n得到的结果组成的集合称为n的剩余系,n的剩余系即小于n的非负整数的集合,记为 Z n Z_n Zn

2.简化剩余系:在n的剩余系中与n互质的元素的集合,称为n的简化剩余系,记为 Z n ∗ Z_n^* Zn

3.欧拉函数:n的简化剩余系中元素的个数,称为欧拉函数,记为 ϕ ( n ) \phi(n) ϕ(n)

4.阶:$g,n $互质,令 g x % n = 1 g^x\%n=1 gx%n=1成立的最小的正整数 x x x,称为 g g g n n n的阶。

5.原根:对于互质的两个正整数 g g g n n n,如果 g g g n n n的阶为 ϕ ( n ) \phi(n) ϕ(n),则称 g g g n n n的原根。换句话说,即对于 1 ≤ j < ϕ ( n ) 1 \leq j < \phi(n) 1j<ϕ(n),使得 g j ≠ 1 ( m o d   n ) g^{j} \neq 1 (mod \ n) gj=1(mod n),但 g ϕ ( n ) = 1 ( m o d   n ) g^{\phi(n)}=1 (mod \ n) gϕ(n)=1(mod n)则称g为n的原根。

使用NTT时有些限制,如果多项式乘法不要求取模,则我们要找足够大的质数 m m m,并且 m − 1 = k × 2 n m−1=k\times2^n m1=k×2n,要保证 2 n 2^n 2n大于等于多项式的次数界, m m m还要大于多项式的系数.

如果多项式乘法是带模乘法,则只能用NTT,不能使用FFT。此时,若 m m m为质数,则要求 m − 1 = k ∗ 2 n m-1=k*2^n m1=k2n,要保证 2 n 2^n 2n要大于等于多项式的次数界, 若 m m m不为质数,则需要用中国剩余定理来做。

NTT

可以发现一些数的简化剩余系在乘法运算下构成的群与FFT当中的单位复根有相似性质。

我们为什么当初FFT要用单位根进行代入?因为单位复根满足一些特殊性质的同时,它还满足当且仅当 i = j i=j i=j ω n i = ω n j \omega_n^i=\omega_n^j ωni=ωnj成立。

如果 m m m存在原根 x x x,则 m m m的简化剩余系 Z m ∗ = { x j ( m o d   m ) ∣ 1 ≤ j ≤ ϕ ( n ) } Z_m^*=\{x^j (mod \ m) |1\leq j \leq \phi(n)\} Zm={xj(mod m)∣1jϕ(n)}
ϕ ( m ) = k ∗ 2 n \phi(m)=k*2^n ϕ(m)=k2n,令 N = 2 n N=2^n N=2n x N i = x ϕ ( m ) ∗ i / N ( m o d   m ) x_N^i=x^{\phi(m)*i/N} (mod \ m) xNi=xϕ(m)i/N(mod m) i ≤ N i \leq N iN
则易知 x N i x_N^i xNi​满足:

1.消去引理
x N d j d ​ = x N j ​ ( m o d   m ) x_{Nd}^{jd}​=x_N^j​(mod\ m) xNdjd=xNj(mod m)
根据定义易证。

2.折半引理
( x N j + N 2 ) 2 = x N 2 j + N = ( x N j ) 2 × x N N = ( x N j ) 2   ( m o d   m ) (x_N^{j+\frac{N}{2}})^2=x_N^{2j+N}=(x_N^j)^2\times x_N^N=(x_N^j)^2 \ (mod \ m) (xNj+2N)2=xN2j+N=(xNj)2×xNN=(xNj)2 (mod m)
根据消去引理易证。

3.求和引理
m > 2 m>2 m>2 k k k不是 N N N的倍数时
∑ j = 0 N − 1 ( x N k ) j = 0   ( m o d   m ) \sum\limits_{j=0}^{N-1} (x_N^k)^j=0 \ (mod \ m) j=0N1(xNk)j=0 (mod m)
根据等比数列求和公式易证。

后记&版题

本篇文章写得还算轻松,因为有很多东西可以借鉴《FFT笔记》

本篇文章借鉴了一些资料:
《快速数论变换(NTT)及蝴蝶操作构造详解》——永远在你身后
快速数论变换NTT——hefenghhhh

下面贴个板子:

code:

#include<bits/stdc++.h>
using namespace std;

#define ll long long
#define rp(i,o,p) for(ll i=o;i<=p;++i)
#define pr(i,o,p) for(ll i=o;i>=p;--i)

const ll MAXN=1e7+5,P=998244353;

ll n=1;
char s1[MAXN],s2[MAXN];
ll ans[MAXN],inv3,omg[MAXN],inv[MAXN];
ll la,lb;
ll a[MAXN],b[MAXN];

ll qpow(ll a,ll b)
{
    ll re=1;
    while(b)
    {
        if(b&1)
            re*=a,re%=P;
        a*=a,a%=P;
        b>>=1;
    }
    return re;
}

void init()
{
    inv3=qpow(3,P-2);
    for(ll i=1;i<=n;i<<=1)
    {
        omg[i]=qpow(3,(P-1)/i);
        inv[i]=qpow(inv3,(P-1)/i);
    }
}

void ntt(ll *a,ll *omg)
{
    for(ll i=0,j=0;i<n;++i)
    {
        if(i>j) swap(a[i],a[j]);
        for(ll l = n >> 1; (j^=l) < l; l >>= 1);
    }
    for(ll l=2;l<=n;l<<=1)
    {
        ll m=l>>1;
        for(ll *p=a;p!=a+n;p+=l)
        {
            ll w=1,wn=omg[l];
            rp(i,0,m-1)
            {
                ll t=w*p[i+m]%P;
                p[i+m]=(p[i]-t+P)%P;
                p[i]=(p[i]+t)%P;
                w=w*wn%P;
            }
        }
    }
}

int main()
{
    scanf("%s%s",s1,s2);
    la=strlen(s1),lb=strlen(s2);
    while(n<la+lb) n<<=1;
    rp(i,0,la-1)
        a[i]=s1[la-i-1]-'0';
    rp(i,0,lb-1)
        b[i]=s2[lb-i-1]-'0';
    
    init();
    ntt(a,omg);
    ntt(b,omg);

    rp(i,0,n-1)
        a[i]=a[i]*b[i]%P;
    
    ntt(a,inv);

    ll invn=qpow(n,P-2);
    rp(i,0,n-1)
    {
        ans[i]+=a[i]*invn%P;
        ans[i+1]+=ans[i]/10;
        ans[i]%=10;
    }
    ll i;
    for(i=la+lb-1;i>=0&&!ans[i];--i)
        if(i==0)
            putchar('0'),i=-1;
    while(i>=0)
        putchar('0'+ans[i--]);
    puts("");

    return 0;
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值