题目链接
思路
相信大家都已经学会了 F F T FFT FFT,若不会,请看这篇博客
一个同学写的,自认为不错
在我们的 F F T FFT FFT中,我们使用了复数来进行计算
但是我们可以发现复数的乘法时间复杂度是 O ( 4 ) O(4) O(4)
而 d o u b l e double double的计算则更加增添了时间复杂度
同时因为浮点数计算 \sqrt{\ \ \ } 的精度会有误差
导致我们最终的所有部分的和反而与完整的 360 360 360°
那么我们不妨试想,若是在系数为整数的情况下
或者需要取模的时候,我们该如何来解决呢?
NTT
于是我们就可以介绍今天的主角了
NTT —— 快速数论变换
是一种建立在数论上的对FFT的优化
(或者可以说是取模运算的FFT)
只不过由于FFT用到是复数
而且double在做了大量的实数运算之后
精度损失较大
而我们的NTT就可以在模意义下
快速做这样的一个多项式乘法
NTT常数小一些
一般这个模数被认为是 x ∗ 2 k + 1 x * 2^k+1 x∗2k+1
原根
接下来我们介绍一个东西——原根
设 m m m是正整数, a a a是整数
若 a a a模 m m m的阶等于 φ ( m ) \varphi(m) φ(m)
则称 a a a为模 m m m的一个原根。
假设一个数 g g g是 P P P的原根
那么 g i m o d P g^i\ mod\ P gi mod P的结果两两不同
且有 1 < g < P 1<g<P 1<g<P, 0 < i < P 0<i<P 0<i<P
归根到底就是 g P − 1 ≡ 1 ( m o d P ) g^{P-1} \equiv 1 (mod\ P) gP−1≡1(mod P)
当且仅当指数为 P − 1 P-1 P−1的时候成立( P P P是素数)。
简单来说, g i m o d p ≠ g j m o d p g^i\ mod\ p \neq g^j mod\ p gi mod p=gjmod p ( p p p为素数)
其中 i ≠ j i \ne j i=j 且 i , j i, j i,j介于 1 1 1至 ( p − 1 ) (p-1) (p−1)之间
则 g g g为 p p p的原根。
提供一种暴力的原根的求法
int calc(int x)// 求原根
{
if (x == 2)
return 1;
for