数论变换NTT

前置知识

  1. FFT:NTT的思想和FFT一样([FFT介绍](%3Ca href="https://www.cnblogs.com/guoshaoyang/p/10957854.html"%3Ehttps://www.cnblogs.com/guoshaoyang/p/10957854.html%3C/a%3E))

概述

数论变换,即NTT(Number Theory Transformation?),是基于数论域的FFT,一般我们默认FFT为负数域上的快速傅里叶变换,和NTT区分。

我们知道,FFT是利用单位复根的周期性,以\(\Theta(N \log N)\)的复杂度计算\(N\)组多项式的值。NTT其实就是在数论域上的FFT,它利用素数取模的周期性,达到了和FFT一样的效果。

原根

若\(a\)模\(P\)的阶等于\(φ(P)\),则称\(a\)为模\(P\)的一个原根(这个定义不重要)。

对于质数\(P\),若\(g\)是\(P\)的原根,那么\(g^i \mod P\)的结果两两不同;或者说\(g^t = 1 (\mod P)\)当且仅当指数为\(t=P-1\)的时候成立。

我们发现,原根的性质和单位负数根的性质一一对应,都满足周期性和周期内互异性,故可以用来代入和插值。

NTT

我们有离散傅里叶变换公式

\[X_k=\sum^{N-1}_{n=0}{x_ne^{-\frac{2\pi i}{N}nk}} \ \ \ \ \ \ \ \ \ \ \ \ (k=0,1,...,N-1)
\]

和逆变换公式

\[X_k=\frac{1}{N}\sum^{N-1}_{n=0}{x_ne^{\frac{2\pi i}{N}nk}} \ \ \ \ \ \ \ \ \ \ \ \ (k=0,1,...,N-1)
\]

我们只需要用原根\(g^{\frac{P-1}{N}} (\mod P)\)替代单位复根\(e^{-\frac{-2\pi i}{N}}\),就可以得到

\[X_k=\sum^{N-1}_{n=0}{x_ng^{\frac{P-1}{N}nk}}(\mod P) \ \ \ \ \ \ \ \ \ \ \ \ (k=0,1,...,N-1)
\]

\[X_k=\frac{1}{N}\sum^{N-1}_{n=0}{x_ng^{-\frac{P-1}{N}nk}}(\mod P) \ \ \ \ \ \ \ \ \ \ \ \ (k=0,1,...,N-1)
\]

实现

和FFT的模板几乎一样,用原根\(g^{\frac{P-1}{N}} (\mod P)\)替代单位复根\(e^{-\frac{-2\pi i}{N}}\)即可

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF=1e9+7,MAXN=3e6+10/*Min:2^20+10*/;
const LL BASE=3,MOD=998244353,INV=332748118;
inline LL fpm(LL base,LL p){
LL ret=1;
while(p){
if(p&1)
ret=ret*base%MOD;
base=base*base%MOD;
p>>=1;
}
return ret%MOD;
}
int N,M,limit=1,lg,rev[MAXN];
inline void NTT(LL *a,int type){
for(int i=0;i<limit;i++)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(int mid=1;mid<limit;mid<<=1){
int len=mid<<1/*n*/;
LL Wn=fpm(type==1?BASE:INV/*BASE^type*/,(MOD-1)/len);
for(int j=0;j<limit;j+=len){
LL w=1;
for(int k=0;k<mid;k++){
int x=a[j+k],y=w*a[j+k+mid]%MOD;
a[j+k]=(x+y)%MOD;
a[j+k+mid]=(x-y+MOD)%MOD;
w=w*Wn%MOD;
}
}
}
}
LL a[MAXN],b[MAXN];
int main(){
scanf("%d%d",&N,&M);
for(int i=0;i<=N;i++){
scanf("%lld",a+i);
a[i]=(a[i]+MOD)%MOD;
}
for(int i=0;i<=M;i++){
scanf("%lld",b+i);
b[i]=(b[i]+MOD)%MOD;
}
while(limit<=N+M){
limit<<=1;
lg++;
}
for(int i=0;i<limit;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1));
NTT(a,1);
NTT(b,1);
for(int i=0;i<limit;i++)
a[i]=a[i]*b[i]%MOD;
NTT(a,-1);
LL limit_inv=fpm(limit,MOD-2);
for(int i=0;i<=N+M;i++)
printf("%lld ",a[i]*limit_inv%MOD);
return 0;
}

复杂度

时间

和FFT一样,是\(\Theta(N \log N)\),在数据较小的情况下比FFT快,但因为其中有快速幂运算,如果数字太大则会导致TLE

空间

和FFT一样,是\(\Theta(N)\),但注意数组大小不是\(N+M\),而是不小于\(N+M\)的最小的\(2\)的幂

范围(素数选取)

我们需要一个大素数来取模,这个素数要大于最终输出的答案(但如果太大,就需要使用快速乘)

下面给出常用的几个素数,原根及原根的逆元

素数 原根 逆元
65537 3 21846
786433 10 235930
5767169 3 1922390
7340033 3 2446678
23068673 3 7689558
104857601 3 34952534
167772161 3 55924054
469762049 3 156587350
998244353 3 332748118
1004535809 3 334845270
2013265921 31 64944062
2281701377 3 760567126
3221225473 5 1932735284
75161927681 3 25053975894
77309411329 7 22088403237
206158430209 22 84337539631
2061584302081 7 589024086309
2748779069441 3 916259689814
6597069766657 5 2638827906663
39582418599937 5 15832967439975
79164837199873 5 47498902319924
263882790666241 7 150790166094995
1231453023109120 3 410484341036374
1337006139375610 3 445668713125206
3799912185593850 5 1519964874237540
4222124650659840 19 888868347507335
7881299347898360 6 1313549891316390
31525197391593400 3 10508399130531100
180143985094819000 6 30023997515803300
1945555039024050000 5 1167333023414430000
4179340454199820000 3 1393113484733270000

NTT数论变换的更多相关文章

  1. 快速傅里叶变换FFT& 数论变换NTT

    相关知识 时间域上的函数f(t)经过傅里叶变换(Fourier Transform)变成频率域上的F(w),也就是用一些不同频率正弦曲线的加 权叠加得到时间域上的信号. \[ F(\omega)=\m ...

  2. 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/常用套路【入门】

    原文链接https://www.cnblogs.com/zhouzhendong/p/Fast-Fourier-Transform.html 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/ ...

  3. 高速数论变换(NTT)

    今天的A题.裸的ntt,但我不会,于是白送了50分. 于是跑来学一下ntt. 题面非常easy.就懒得贴了,那不是我要说的重点. 重点是NTT,也称高速数论变换. 在非常多问题中,我们可能会遇到在模意 ...

  4. 从傅里叶变换(FFT)到数论变换(NTT)

    FFT可以用来计算多项式乘法,但是复数的运算中含有大量的浮点数,精度较低.对于只有整数参与运算的多项式,有时,\(\text{NTT(Number-Theoretic Transform)}\)会是更 ...

  5. 【算法】快速数论变换(NTT)初探

    [简介] 快速傅里叶变换(FFT)运用了单位复根的性质减少了运算,但是每个复数系数的实部和虚部是一个余弦和正弦函数,因此系数都是浮点数,而浮点数的运算速度较慢且可能产生误差等精度问题,因此提出了以数论 ...

  6. Algorithm: 多项式乘法 Polynomial Multiplication: 快速傅里叶变换 FFT / 快速数论变换 NTT

    Intro: 本篇博客将会从朴素乘法讲起,经过分治乘法,到达FFT和NTT 旨在能够让读者(也让自己)充分理解其思想 模板题入口:洛谷 P3803 [模板]多项式乘法(FFT) 朴素乘法 约定:两个多 ...

  7. 「算法笔记」快速数论变换(NTT)

    一.简介 前置知识:多项式乘法与 FFT. FFT 涉及大量 double 类型数据操作和 \(\sin,\cos\) 运算,会产生误差.快速数论变换(Number Theoretic Transfo ...

  8. NTT 快速数论变换

    NTT 先学习FFT 由于FFT是使用复数运算,精度并不好,而且也无法取模,所以有了NTT(快速数论变换). 建议先完全理解FFT后再学习NTT. 原根 NTT使用与单位根性质相似的原根来代替单位根. ...

  9. 快速傅里叶变换 & 快速数论变换

    快速傅里叶变换 & 快速数论变换 [update 3.29.2017] 前言 2月10日初学,记得那时好像是正月十五放假那一天 当时写了手写版的笔记 过去近50天差不多忘光了,于是复习一下,具 ...

随机推荐

  1. mongodb 可视化工具

    mongodb是用命令行输入的,有些人可能不太习惯,我自己找了下mongodb的一些可视化工具,发现了一款adminmongo很好用,这里介绍给你们用一下. github地址:https://gith ...

  2. css 一行内显示 超出自动隐藏

    一般的文字截断(适用于内联与块): Example Source Code [www.mb5u.com].text-overflow {display:block;/*内联对象需加*/width:31 ...

  3. macOS截屏

    Command+Shift+3: 全屏幕截屏,并自动保存在桌面 Command+Shift+4: 手动截屏,并自动保存在桌面 Command+Shift+4, + Space, 之后点击程序的窗口,实 ...

  4. Java高并发网络编程(一)

    一.OSI网络七层模型 因特网是一个极为复杂的网络,分层有助于我们对网络的理解 .分层也是一种标准,为了使不同厂商的计算机能够互相通信,以便在更大范围内建立计算机网络,有必要建立一个国际范围的网络体系 ...

  5. php操作redis--列表篇

    常用函数:lpush/rpush/lpop/rpop/lrange/lrem等 应用场景:关注列表,粉丝列表,发送缓冲队列等 特点:可理解为数组操作,插入和删除数据按照一定的规律排序,数据可重复 连接 ...

  6. common配置文件

    <dependencies> <dependency> <groupId>com.github.pagehelper</groupId> <art ...

  7. Repeatable Read

    在Repeatable Read隔离级别下,一个事务可能会遇到幻读(Phantom Read)的问题. 幻读是指,在一个事务中,第一次查询某条记录,发现没有,但是,当试图更新这条不存在的记录时,竟然能 ...

  8. Mac上安装Android SDK

    今天开始学习IOS,所以先买了个设备先,但是开始使用了苹果本,还是需要继续开发Android,因为那是我现在吃饭的东西,所以就需要在Mac上配置Android SDK,原以为安装SDK很简单,和Win ...

  9. Web移动端常见问题-摘抄

      一.按钮点击时出现黑色背景 解决方法: 1 2 .class { -webkit-tap-highlight-color:rgba(0,0,0,0);} .class { -webkit-appe ...

  10. MySQL数据库(三)—— 表相关操作(二)之约束条件、关联关系、复制表

    表相关操作(二)之约束条件.关联关系.复制表 一.约束条件  1.何为约束 除了数据类型以外额外添加的约束 2.约束条件的作用 为了保证数据的合法性,完整性 3.主要的约束条件 NOT NULL # ...