首页 > 其他分享 >NTT笔记

NTT笔记

时间:2023-05-04 21:23:10浏览次数:41  
标签:phi ll FFT NTT 笔记 MAXN mod

NTT 笔记

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

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

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

NTT 有什么用

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

为什么要用 NTT

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

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

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

2.简化剩余系:在n的剩余系中与n互质的元素的集合,称为n的简化剩余系,记为 \(Z_n^*\)。

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

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

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

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

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

NTT

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

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

如果\(m\)存在原根\(x\),则\(m\)的简化剩余系 \(Z_m^*=\{x^j (mod \ m) |1\leq j \leq \phi(n)\}\)。
设\(\phi(m)=k*2^n\),令\(N=2^n\), \(x_N^i=x^{\phi(m)*i/N} (mod \ m)\),\(i \leq N\)。
则易知\(x_N^i\)​满足:

1.消去引理

\[x_{Nd}^{jd}​=x_N^j​(mod\ m) \]

根据定义易证。

2.折半引理

\[(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) \]

根据消去引理易证。

3.求和引理
当\(m>2\)且\(k\)不是\(N\)的倍数时

\[\sum\limits_{j=0}^{N-1} (x_N^k)^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;
}

标签:phi,ll,FFT,NTT,笔记,MAXN,mod
From: https://www.cnblogs.com/Wang-Holmes/p/17372538.html

相关文章

  • 「学习笔记」可持久化线段树
    可持久化数据结构(Persistentdatastructure)总是可以保留每一个历史版本,并且支持操作的不可变特性(immutable)。主席树全称是可持久化权值线段树,给定\(n\)个整数构成的序列\(a\),将对于指定的闭区间\(\left[l,r\right]\)查询其区间内的第\(k\)小值。可持久化线段......
  • STL源码分析读书笔记
    主要是关于标准库容器的整理空间配置器主要看SGI的实现,有两个空间配置器_malloc_alloc_template<0>__default_alloc_template<...>用户可以选择单独使用第一个分配器,或者一起使用两个分配器。当用户选择使用两个分配器时,编译器会分别将上述两个分配器typedef成malloc_a......
  • 23.4.24前学习笔记
    可通过document.documentElement.scrollTop=0控制返回页面顶部 scrollTo方法 window.scrollTo(x,y)//控制页面移动到哪  页面尺寸事件 window.addEventListener('resize',function(){    //改变屏幕尺寸时发生变化,可代替媒体查询    letw=documen......
  • Java学习笔记(九)
    1、代理模式的概念可以为其它对象提供一种代理以控制对这个对象的访问,屏蔽对真实角色的直接访问。2、为什么要重写toString()方法?默认情况下,toString()方法返回的字符串是由对象的类名、“@”符号和对象的哈希码组成的。我们需要重写toString()方法,以便返回更有意义和有用的字......
  • vue-esign 学习笔记
    1注意事项最新版是1.1.4,我们项目组用的是1.1.0。从npmjs可以看出,两个版本中间的版本都是不可用的,下载量为0.除此之外还可以参考的类似工具:https://www.npmjs.com/package/vue-esignaturevue-esignaturehttps://www.npmjs.com/package/vue3-esignvue3-esign2链接地址http......
  • FFT&NTT学习笔记
    概念多项式乘法时,我们发现暴力乘十分缓慢,但是点值乘十分快速。考虑求\(A\)和\(B\)的卷积。一个\(n\)次多项式可以被\(n+1\)个点确定。设多项式\(A(x)\)的系数为\((a_0,a_1,\cdots,a_n)\)对其奇偶分类得\(A(x)=\sum\limitsa_{2i}*x^{2i}+\suma_{2i+1}*x^{2i+1}\)......
  • 学习笔记:矩阵快速幂
    1.矩阵乘法设矩阵有\(H\)行,\(L\)列,则两个矩阵\(MatA,MatB\)进行乘法,需要满足\(MatA.L=MatB.H\)。则结果矩阵\(MatR_{i,j}=\sum\limits^{n}_{z=1}MatA_{i,z}*MatB_{z,j}\)。性质:结合律,但不满足交换律。matoperator*(mata,matb){ matc; memset(c.mat,0,sizeof(c.......
  • 树链剖分学习笔记
    一棵树,支持:路径加单点查询一般树上链的问题使用树链剖分解决。重链剖分前置知识LCA,线段树定义重儿子:所有儿子中子树最大的儿子为重儿子重边:重儿子之间的连边重链:若干重儿子连成的链性质一棵树可以被剖成若干重链。优先遍历重儿子,所有重链的dfs序连续。重链数量不......
  • 生成函数学习笔记
    概念序列的母函数(生成函数)是一种形式幂级数。其每一项的系数可以提供关于这个序列的信息,使用母函数解决问题。如:序列\(a\)的生成函数为\(G(x)=\sum\limits_{i=1}^{n}a_if_i(x)\)。其中\(f_i(x)\)是无实际意义的,具体取值看题目要求。但有一些一般取值。一般生成函数令\(f......
  • 拉格朗日插值学习笔记
    拉格朗日插值学习笔记概念拉格朗日插值用于拟合一个函数。可以通过已知函数中的点拟合出函数。若为\(n\)次函数,则需要多于\(n+1\)个点。做法考虑构造\(n+1\)个函数,第\(i\)个函数\(f_i\)对应点\(i\)满足\(f_i(X_i)=Y_i\)且对于其他的点\(j(i\neqj)\)满足\(f_......