快速数论变换 | NTT 初学
快速数论变换 | NTT 初学
前置
-
原根
阶:称满足同余方程
的最小正整数解 为 的模 的阶,记为
。观察到本质就是最短循环节,同时该同余方程类似于欧拉定理:
那么显然两者的关系是
。特别地,当 时,我们称 是 的一个原根。下面给出三个有关原根和阶的事实。
-
若有
,则 的阶 满足 。证明:
将
带余除法表示成 的形式,其中, 。那么显然有 。那么可得因为
是满足 的最小正整数解,故有 ,也即 ,故 。 -
一个数
是模 的原根当且仅当 可以生成所有的可逆元,也即任何与 互质 的整数 , , 。证明:
若
不是模 的原根,那么其阶必定 ,不同于 的次方就少于 个,但是可逆元是数量为 ,显然不可以生成所有可逆元。若
是模 的原根, 的前 个正整数次方分别为 。我们尝试用反证法说明这 个数模 的结果互不相同。假设存在 满足 。那么必定有 ,因为 ,显然与 矛盾。所以有
前 次方对 取模的余数恰好是与 互质的 个余数的重排后的结果,并且有 。 -
设
是模 的一个原根,那么 是原根,当且仅当 。证明:
当
与 互质时,一定可以找到一组 满足 。故对于 任意次方 都有:也即,
在同于意义下可以表示成 的 次方,这说明 可生成所有可逆元,故 为模 的逆元。
原根的存在性:
原根存在的充要条件是模数能表示成 ,其中 是一个奇质数。其数量为 。原根要怎么求?由前面有关原根的事实可知,要判断一个数
是否是 的原根,将 质因数分解成 。那只需要检验 中是否存在一个数 使得 。时间复杂度 ,其中 为 的质因子个数。当 时, ,时间开销极小。 -
NTT
快速傅里叶变换中选定单位根做多项式乘法,其劣势在于无法保证浮点数的精度。考虑用原根替换,会发现它依然满足单位根的三个引理:消去引理、折半引理、求和引理。
void NTT(int *e, int op) {
for(int i = 0; i < lim; i++) {
if(i < p[i]) swap(e[i], e[p[i]]); // 蝴蝶变换
}
for(int k = 1; k < lim; k <<= 1) { // 迭代
long long pw = Pow((op == -1 ? Pow(3, Mod - 2) : 3), (Mod - 1) / (k << 1)); // 原根替换单位根
for(int i = 0; i < lim; i += k << 1) {
for(int j = i, o = 1; j < i + k; j++, o = o * pw % Mod) {
int x = e[j];
int y = e[j + k];
e[j] = (x + y * o % Mod) % Mod;
e[j + k] = (x - y * o % Mod + Mod) % Mod;
}
}
}
if(op == -1) {
for(int i = 0; i < lim; i++) {
e[i] = e[i] * Pow(lim, Mod - 2) % Mod;
}
}
}
FFT/NTT 匹配字符串
现有文本串
设
因为完全匹配,所以有
为了统一下标,将
这样就可以用FFT/NTT 求解了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效