多项式多项式多项式多像💩多项式多项式多项式
一些定义
单位根
xn=1 在复数域内的n个解,我们把这些解称为单位根
wnk 其中 k∈[0,n−1] ,单位根把单位圆n等分
单位根的性质
wnn=1
wnk+n=wnk 画图理解
wnk+2n=−wnk 画图理解
wdkdk=wnk 约分?
单位根反演
[k∣n]=k1i=0∑k−1wkni
多项式的表示
对于一个多项式 f(x)=i=0∑naixi
我们可以通过系数即 (a0,a1,a2,..,an) 表示这个多项式 称为 系数表示
还有一种表示,叫做 点值表示
我们知道对于一个 n 次多项式 它可以由 n+1 个多项式上的点值确定
就是用这 n+1 个点值来表示这个多项式
FFT
可以快速解决多项式乘法问题
例如 A(x)∗B(x)=C(x) 那么 C(x) 的次数就是 A 和 b 加起来
先整点朴素的嗷 一项一项乘上去的复杂度为 O(n2)
我们需要进行一些优化
考虑用点值来操作
用点痣表示 A 和 B
A(x)={(x0,A(x0)),(x1,A(x0)),(x2,A(x2)),...,(xn,A(xn))}B(x)={(x0,B(x0)),(x1,B(x0)),(x2,B(x2)),...,(xn,B(xn))}
那么
C(x)={(x0,A(x0)∗B(x0)),...,((xn+m),A(xn+m)∗B(xn+m))}
所以我们现在可以在 O(n) 的时间内计算了
我们还需要把系数表示换位点值表示 再把结果的点值表示换位系数表示
第一步 DFT
系数 → 点值
把项数按奇偶分开考虑
\begin{align}
A(x) &= \sum\limits_{i = 0}^n a_ix^i\nonumber \\
&=(a_0 + a_2x^2 +a_4x^4+\dots+a_{n-2}x^{n-2})\nonumber \\
&+(a_1x+a_3{x^3}+a_5{x^5}+ \dots+a_{n-1}x^{n-1})\nonumber
\end{align}
令
\begin{align}
A_1(x) &= (a_0 + a_2x +a_4x^2+\dots+a_{n-2}x^{\frac{n}{2}-1})\nonumber\\
A_2(x) &= (a_1x+a_3x+a_5{x^2}+ \dots+a_{n-1}x^{\frac{n}{2}-1})\nonumber
\end{align}
那么
A(x)=A1(x2)+xA2(x2)
我们把 x=wnk 代入
A(wnk)=A1(wn2k)+wnkA2(wn2k)
再带个 x=wnk+2n
\begin{align}
A(w_n^{k+\frac{n}{2}})
&= A_1(w_n^{2k+n}) + w_n^{k+\frac{n}{2}}A_2(w_n^{2k+n})\nonumber\\
&=A_1(w_n^{2k}) - w_n^kA_2(w_n^{2k})\nonumber
\end{align}
wnn=1
wnk+2n=−wnk
我们观察得到的两个狮子,发现只有 A2 的系数不同
我们可以递归求出 wnk 的 A1 和 A2 来计算 A
第二步 IDFT
点值 → 系数
IDFT(Inv_DFT) DFT的逆过程
从定义出发
Ci=Aj∗Bi=j=0∑i−1aj∗bi−j−1
令 q=j,p=i−j−1
则 Ci=p∑q∑ap∗bq[p+q==n]
=p∑q∑ap∗bq[n∣p+q−i]
单位根反演
=∑p∑qap∗bqj=0∑n1wn(p+q−i)j
那么
nCi=∑p∑qap∗bqj=0∑wn(p+q−i)j
把 p,q,i 分配一下,再把 j 提到前边去
nCi=∑jwn−ij(∑pwnjpap)(∑qwnjqbq)
后面两个 ∑ 貌似就是 A 和 B 在 wnj 的点值?就是我们 DFT 的结果
于是我们代入 wnj 再DFT一遍就能得到 A−1
还有更酷炫的 O(n) 方法
观察我们按奇偶拆开时的结果
恰好是原序列下标的二进制反转一下,我们就可以省去按奇偶分类的时间但是不会写
Code
递归版本儿 蒟蒻不会写非递归的捏
cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| #include<cstdio> #include<cmath> #define MAXN 3000005 using namespace std; struct complex { double x,y; complex operator + (complex b) {return complex{x+b.x, y+b.y};} complex operator - (complex b) {return complex{x-b.x, y-b.y};} complex operator * (complex b) {return complex{x*b.x - y*b.y, x*b.y + y*b.x};} }A[MAXN],B[MAXN]; int n,m;
const double pi = acos(-1.0);
void FFT(int limit, complex *a, int opt) { if(limit == 1) return; complex a1[limit>>1], a2[limit>>1]; for(int i = 0; i < limit; i += 2) { a1[i>>1] = a[i]; a2[i>>1] = a[i+1]; } FFT(limit>>1, a1, opt); FFT(limit>>1, a2, opt); complex wn = complex{cos(2.0 * pi/limit), opt*sin(2.0*pi/limit)}; complex w = complex{1, 0}; for(int i = 0; i < (limit>>1); i++, w = w*wn) { a[i] = a1[i] + w*a2[i]; a[i + (limit>>1)] = a1[i] - w*a2[i]; } } int main() { scanf("%d%d",&n,&m); for(int i = 0; i <= n; i++) scanf("%lf", &A[i].x); for(int i = 0; i <= m; i++) scanf("%lf", &B[i].x); int lmt = 1; while(lmt <= n+m) lmt <<= 1; FFT(lmt, A, 1); FFT(lmt, B, 1); for(int i = 0; i <= lmt; i++) A[i] = A[i] * B[i]; FFT(lmt, A, -1); for(int i = 0; i <= n+m; i++) printf("%d ", (int)(A[i].x/lmt+0.5)); }
|
NTT
我们看到在 FFT 中,复数和三角函数会损失很大的精度,也有了不能取模的限制,所以也有另一个做法–NTT
原根 的性质和单位根很相似
令 g 为 模 p 下的原根,我们有 gp−1≡1 (mod p) ,所以可以把单位根 wnk 换成 gnk
一般的 NTT 模数 998244353
的原根为 3
看到别的模数需要考虑一下原根是几或者写多模数 NTT ,但我不会,所以选择寄掉
NTT
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| void NtT(ll *A, int opt) { for(int i = 0; i < limit; i++) if(i < r[i]) swap(A[i], A[r[i]]); for(int mid = 1; mid < limit; mid <<= 1) { ll wn = ksm(opt == 1 ? yp : zp, (p-1)/(mid << 1)); for(int j = 0; j < limit; j += (mid << 1)) { ll w = 1; for(int k = 0; k < mid; k++, w = w*wn%p) { ll x = A[j + k], y = w * A[j + k + mid]%p; A[j + k] = (x + y)%p; A[j + k + mid] = (x - y +p)%p; } } } }
|
多项式求逆
对于一个多项式 F 如果有
F∗G≡1 (mod xn)
那么称 G 即 F−1 为 F 的逆元
既然有
F∗G≡1 (mod xn)
那么同样
\begin{align}
F * H &\equiv 1 \ (mod \; x^{\frac{n}{2}}) \nonumber\\
G &\equiv H (mod \; x^{\frac{n}{2}}) \nonumber\\
(G - H) &\equiv 0 (mod \; x^{\frac{n}{2}}) \nonumber\\
(G - H)^2 &\equiv 0 (mod \; x^n) \nonumber\\
G^2 + H^2 - 2GH &\equiv 0 (mod \; x^n) \nonumber\\
F(G^2 + H^2 - 2GH) &\equiv 0 (mod \; x^n) \nonumber\\
G + FH^2 - 2H &\equiv 0 (mod \; x^n) \nonumber\\
G &\equiv 2H - FH^2 (mod \; x^n) \nonumber
\end{align}
推出式子递归 🆘 完了
多项式对数函数 (多项式 ln )
多项式 F(x) 和 G(x) , G≡lnF(modxn) ,求 G
得 🔪 一下
\begin{align}
G &\equiv \ln F \; (mod \; x^n) \nonumber\\
G' &\equiv \ln F' \; (mod \; x^n) \nonumber\\
G &\equiv \ln(F)' F' \; (mod \; x^n) \nonumber\\
G &\equiv \frac{F'}{F} \; (mod \; x^n) \nonumber
\end{align}
所以求个导再整一个 F 的逆元得到 G′ 再寄回去就行辣
多项式指数函数 (多项式 exp
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa