Loading docs/math/poly-div-mod.mddeleted 100755 → 0 +0 −130 Original line number Diff line number Diff line ## Description 给定多项式 $f\left(x\right),g\left(x\right)$,求 $g\left(x\right)$ 除 $f\left(x\right)$ 的商 $Q\left(x\right)$ 和余数 $R\left(x\right)$. ## Method 发现若能消除 $R\left(x\right)$ 的影响则可直接[**多项式求逆**](../poly-inv)解决. 考虑构造变换 $$f^{R}\left(x\right)=x^{\operatorname{deg}{f}}f\left(\frac{1}{x}\right)$$ 观察可知其实质为反转 $f\left(x\right)$ 的系数. 设 $n=\operatorname{deg}{f},m=\operatorname{deg}{g}$. 将 $f\left(x\right)=Q\left(x\right)g\left(x\right)+R\left(x\right)$ 中的 $x$ 替换成 $\frac{1}{x}$ 并将其两边都乘上 $x^{n}$,得到: $$\begin{aligned} f\left(\frac{1}{x}\right)&=x^{n-m}Q\left(x\right)x^{m}g\left(x\right)+x^{n-m+1}x^{m-1}R\left(x\right)\\ f^{R}\left(x\right)&=Q^{R}\left(x\right)g^{R}\left(x\right)+x^{n-m+1}R^{R}\left(x\right) \end{aligned}$$ 注意到上式中 $R^{R}\left(x\right)$ 的系数为 $x^{n-m+1}$,则将其放到模 $x^{n-m+1}$ 意义下即可消除 $R^{R}\left(x\right)$ 带来的影响. 又因 $Q^{R}\left(x\right)$ 的次数为 $\left(n-m\right)<\left(n-m+1\right)$,故 $Q^{R}\left(x\right)$ 不会受到影响. 则: $$f^{R}\left(x\right)\equiv Q^{R}\left(x\right)g^{R}\left(x\right)\pmod{x^{n-m+1}}$$ 使用多项式求逆即可求出 $Q\left(x\right)$,将其反代即可得到 $R\left(x\right)$. 时间复杂度 $O\left(n\log{n}\right)$. ## Code ??? " `poly-div-mod.cpp` " ```cpp using Z=int; using mZ=long long; using poly_t=Z[mxdg]; using poly=Z*const; inline int calcpw2(const int&n){ int t=1; for(;t<n;t<<=1); return t; } inline void cp(const Z*const&sl,const Z*const&sr,Z*const&dl,Z*const&dr){ std::copy(sl,sr,dl); if(sr-sl<dr-dl) std::fill(dl+(sr-sl),dr,0); } void polydiv(const poly&f,const int&n,const poly&g,const int&m,poly&Q,poly&R){ static poly_t div_t; const int res=n-m+1; const int deg1=calcpw2(res+res); std::reverse_copy(g,g+m,Q); if(m<deg1) std::fill(Q+m,Q+deg1,0); polyinv(Q,div_t,res); std::reverse_copy(f+m-1,f+n,Q); std::fill(Q+res,Q+deg1,0); DFT(Q,deg1);DFT(div_t,deg1); for(int i=0;i!=deg1;++i) Q[i]=(mZ)Q[i]*div_t[i]%p; IDFT(Q,deg1); std::reverse(Q,Q+res); std::fill(Q+res,Q+deg1,0); const int deg2=calcpw2(n); cp(Q,Q+res,R,R+deg2); cp(g,g+m,div_t,div_t+deg2); DFT(R,deg2);DFT(div_t,deg2); for(int i=0;i!=deg2;++i) R[i]=(mZ)R[i]*div_t[i]%p; IDFT(R,deg2); for(int i=0;i!=m;++i) R[i]=sub(f[i],R[i]); std::fill(R+m-1,R+deg2,0); } void polymod(const poly&f,const int&n,const poly&g,const int&m,poly&R){ static poly_t mod_t; const int res=n-m+1; const int deg1=calcpw2(res+res); std::reverse_copy(g,g+m,R); if(m<deg1) std::fill(R+m,R+deg1,0); polyinv(R,mod_t,res); std::reverse_copy(f+m-1,f+n,R); std::fill(R+res,R+deg1,0); DFT(R,deg1);DFT(mod_t,deg1); for(int i=0;i!=deg1;++i) R[i]=(mZ)R[i]*mod_t[i]%p; IDFT(R,deg1); std::reverse(R,R+res); std::fill(R+res,R+deg1,0); const int deg2=calcpw2(n); cp(g,g+m,mod_t,mod_t+deg2); DFT(R,deg2);DFT(mod_t,deg2); for(int i=0;i!=deg2;++i) R[i]=(mZ)R[i]*mod_t[i]%p; IDFT(R,deg2); for(int i=0;i!=m;++i) R[i]=sub(f[i],R[i]); std::fill(R+m-1,R+deg2,0); } ``` docs/math/poly/div-mod.md 0 → 100755 +34 −0 Original line number Diff line number Diff line ## Description 给定多项式 $f\left(x\right),g\left(x\right)$,求 $g\left(x\right)$ 除 $f\left(x\right)$ 的商 $Q\left(x\right)$ 和余数 $R\left(x\right)$。 ## Method 发现若能消除 $R\left(x\right)$ 的影响则可直接[**多项式求逆**](../poly-inv)解决. 考虑构造变换 $$f^{R}\left(x\right)=x^{\operatorname{deg}{f}}f\left(\frac{1}{x}\right) $$ 观察可知其实质为反转 $f\left(x\right)$ 的系数。 设 $n=\operatorname{deg}{f},m=\operatorname{deg}{g}$。 将 $f\left(x\right)=Q\left(x\right)g\left(x\right)+R\left(x\right)$ 中的 $x$ 替换成 $\frac{1}{x}$ 并将其两边都乘上 $x^{n}$,得到: $$ \begin{aligned} f\left(\frac{1}{x}\right)&=x^{n-m}Q\left(x\right)x^{m}g\left(x\right)+x^{n-m+1}x^{m-1}R\left(x\right)\\ f^{R}\left(x\right)&=Q^{R}\left(x\right)g^{R}\left(x\right)+x^{n-m+1}R^{R}\left(x\right) \end{aligned} $$ 注意到上式中 $R^{R}\left(x\right)$ 的系数为 $x^{n-m+1}$,则将其放到模 $x^{n-m+1}$ 意义下即可消除 $R^{R}\left(x\right)$ 带来的影响。 又因 $Q^{R}\left(x\right)$ 的次数为 $\left(n-m\right)<\left(n-m+1\right)$,故 $Q^{R}\left(x\right)$ 不会受到影响。 则: $$f^{R}\left(x\right)\equiv Q^{R}\left(x\right)g^{R}\left(x\right)\pmod{x^{n-m+1}}$$ 使用多项式求逆即可求出 $Q\left(x\right)$,将其反代即可得到 $R\left(x\right)$。 时间复杂度 $O\left(n\log{n}\right)$。 docs/math/fft.md→docs/math/poly/fft.md +24 −24 Original line number Diff line number Diff line (本页面部分内容转载自[桃酱的算法笔记](https://zhuanlan.zhihu.com/c_1005817911142838272),原文戳[链接](https://zhuanlan.zhihu.com/p/41867199),已获得作者授权) 一直想学 FFT,之前牛客的多小有一道组合数学就用 FFT 写的,而且当时还傻乎乎的用唯一分解定理,但是自己好久没静下心学什么了,而且自己的数学功底又不好,导致一直学不会。看了很多人的博客也没看明白,尤其是原根。在我看了几十篇博客之后终于看懂了……所以想写一篇能够让大多数人都看得懂的教程。花费时间 3 天终于写完啦~~~~\~~ 一直想学 FFT,之前牛客的多校有一道组合数学就用 FFT 写的,而且当时还傻乎乎的用唯一分解定理,但是自己好久没静下心学什么了,而且自己的数学功底又不好,导致一直学不会。看了很多人的博客也没看明白,尤其是原根。在我看了几十篇博客之后终于看懂了……所以想写一篇能够让大多数人都看得懂的教程。花费时间 3 天终于写完啦~~~~\~~ 另外,本文 FFT 部分的代码实现全部参考 kuangbin 的模板(2018.7 更新)资源地址如下 Loading Loading @@ -100,7 +100,7 @@ $$ 。另外, $i$ 对于虚数的意义,与 $1$ 对于实数的意义是一样的。如果我说得不够明确,你可以看下面我引用的百科说明。 > 在数学中,虚数就是形如 $a+b \times i$ 的数,其中 $a,b$ 是实数,且 $b \neq 0$ , $i^2 = - 1$ 。虚数这个名词是 17 世纪著名数学家笛卡尔创立,因为当时的观念认为这是真实不存在的数字。后来发现虚数 $a+b \times i$ 的实部 $a$ 可对应平面上的横轴,虚部 $b$ 与对应平面上的纵轴,这样虚数 $a+b \times i$ 可与平面内的点 $(a,b)$ 对应。 > 在数学中,虚数就是形如 $a+b \times i$ 的数,其中 $a,b$ 是实数,且 $b \neq 0$ , $i^2 = - 1$ 。虚数这个名词是 17 世纪著名数学家笛卡尔创立,因为当时的观念认为这是真实不存在的数字。后来发现虚数 $a+b \times i$ 的实部 $a$ 可对应平面上的横轴,虚部 $b$ 与对应平面上的纵轴,这样虚数 $a+b \times i$ 可与平面内的点 $(a,b)$ 对应。 > > 可以将虚数 $bi$ 添加到实数 $a$ 以形成形式 $a + bi$ 的复数,其中实数 $a$ 和 $b$ 分别被称为复数的实部和虚部。一些作者使用术语纯虚数来表示所谓的虚数,虚数表示具有非零虚部的任何复数。——百度百科 Loading Loading @@ -160,7 +160,7 @@ $$ (因为他的角度是相当于单位角度),就能知道 $\omega_4^0, \omega_4^1, \omega_4^2, \omega_4^3$ 了呢?当然是这样的…… $\omega_4^0$ 恒等于 $1$ , $\omega_4^2$ 的角度是 $\omega_4^0$ 的两倍,所以 $\omega_4^2 = (\omega_4^1)^2 = i^2=-1$ , 依次以此类推。 $\omega_4^0$ 恒等于 $1$ , $\omega_4^2$ 的角度是 $\omega_4^0$ 的两倍,所以 $\omega_4^2 = (\omega_4^1)^2 = i^2=-1$ , 依次以此类推。 因此,我们只要知道 $\omega_k^1$ ,就能求出 $\omega_k^n$ 。所以我们把 $\omega_k^1$ 称为单位复根,简写为 $\omega_k$ Loading Loading @@ -216,13 +216,13 @@ $$ !前方高能: 这个函数能处理的多项式长度只能是 $2^m(m \in N^ \times )$ , 否则在分治的时候左右不一样长,右边取不到系数了,程序没法进行。所以要在第一次 DFT 之前就把序列向上补成长度为 $2^m(m \in N^ \times )$ (高次系数补 $0$ )、最高项次数为 $n-1$ 的多项式。一定要预处理哦 这个函数能处理的多项式长度只能是 $2^m(m \in N^ \times )$ , 否则在分治的时候左右不一样长,右边取不到系数了,程序没法进行。所以要在第一次 DFT 之前就把序列向上补成长度为 $2^m(m \in N^ \times )$ (高次系数补 $0$ )、最高项次数为 $n-1$ 的多项式。一定要预处理哦 然后我在代入值的时候,因为要代入 $n$ 个不同值,所以我们就代入 $\omega_n^0,\omega_n^1,\omega_n^2,\cdots, \omega_n^{n-1} (n=2^m(m \in N^ \times ))$ 一共 $2^m$ 个不同值。 ```c++ ```cpp /* * 做 FFT *len 必须是 2^k 形式 Loading Loading @@ -260,7 +260,7 @@ void fft(Complex y[], int len, int on) { 这里附上代码 ```c++ ```cpp /* * 进行 FFT 和 IFFT 前的反置变换 * 位置 i 和 i 的二进制反转后的位置互换 Loading Loading @@ -333,7 +333,7 @@ $$ 记 $S\left(\omega_n^a\right)=\sum_{i=0}^{n-1}\left(\omega_n^a\right)^i$。 当 $a=0$ 时,$S\left(\omega_n^a\right)=n$. 当 $a=0$ 时,$S\left(\omega_n^a\right)=n$。 当 $a\neq 0$ 时,我们错位相减一下 Loading Loading @@ -371,7 +371,7 @@ $$ 所以我们 fft 函数可以集 DFT 和 IDFT 于一身。见下 ```c++ ```cpp /* * 做 FFT *len 必须是 2^k 形式 Loading Loading @@ -405,7 +405,7 @@ void fft(Complex y[], int len, int on) { 好了现在附上全部代码([HDU 1402](http://acm.hdu.edu.cn/showproblem.php?pid=1402)),序言说过代码来自 kuangbin 的模板~~~~~ ```c++ ```cpp #include <cmath> #include <cstdio> #include <cstring> Loading docs/math/fwt.md→docs/math/poly/fwt.md +11 −15 Original line number Diff line number Diff line Loading @@ -6,23 +6,19 @@ 其实这个变换在信号处理中应用很广泛,fft 是 double 类型的,但是 walsh 把信号在不同震荡频率方波下拆解,因此所有的系数都是绝对值大小相同的整数,这使得不需要作浮点数的乘法运算,提高了运算速度。 所以,FWT 和 FFT 的核心思想应该是相同的。都是对数组的变换。我们设数组 $A$ 经过快速沃尔什变换之后记作 $FWT[A]$ . 所以,FWT 和 FFT 的核心思想应该是相同的,都是对数组的变换。我们记对数组 $A$ 进行快速沃尔什变换后得到的结果为 $FWT[A]$ 。 那么 FWT 核心思想就是: 我们需要一个新序列 $C$ ,由序列 $A$ 和序列 $B$ 经过某运算规则得到,即 $C = A \cdot B$ 我们需要一个新序列 $C$ ,由序列 $A$ 和序列 $B$ 经过某运算规则得到,即 $C = A \cdot B$ ; 我们先正向得到 $FWT[A], FWT[B]$ 我们先正向得到 $FWT[A], FWT[B]$,再根据 $FWT[C]=FWT[A] \cdot FWT[B]$ 在 $O(n)$ 的时间复杂度内求出 $FWT[C]$ ; 然后根据 $FWT[C]=FWT[A] \cdot FWT[B]$ 在 $O(n)$ 求出 $FWT[C]$ 然后逆向想运算得到原序列 $C$ 。时间复杂度为 $O(nlogn)$ 然后逆向运算得到原序列 $C$ 。时间复杂度为 $O(n \log{n})$。 在算法竞赛中,FWT 是用于解决对下标进行位运算卷积问题的方法。 公式: $C[i] = \sum_{i=j \bigoplus k}A[j] * B[k]$ 公式: $C_{i} = \sum_{i=j \bigoplus k}A_{j} B_{k}$ (其中 $\bigoplus$ 是二元位运算中的某一种, $*$ 是普通乘法) Loading @@ -38,9 +34,9 @@ 现在要得到 $FWT[C] = FWT[A] * FWT[B]$ ,我们就要构造这个 fwt 的规则。 我们按照定义,显然可以构造 $FWT[A] = A' = \sum_{i=i|j}A[j]$ ,来表示 $j$ 满足二进制中 $1$ 为 $i$ 的子集。 我们按照定义,显然可以构造 $FWT[A] = A' = \sum_{i=i|j}A_{j}$ ,来表示 $j$ 满足二进制中 $1$ 为 $i$ 的子集。 那么显然会有 $C[i] = \sum_{i=j|k}A[j]*B[k] \Rightarrow FWT[C] = FWT[A] * FWT[B]$ 那么显然会有 $C_{i} = \sum_{i=j|k}A_{j}*B_{k} \Rightarrow FWT[C] = FWT[A] * FWT[B]$ 那么我们接下来看 $FWT[A]$ 怎么求。 Loading @@ -56,7 +52,7 @@ $$ 其中 merge 表示像字符串拼接一样把它们拼起来, $+$ 就是普通加法,表示对应二进制位相加。 这样我们就通过二分能在 $O(logn)$ 完成拼接,每次拼接的时候要完成一次运算,也就是说在 $O(nlogn)$ 的时间复杂度得到了 $FWT[A]$ 。 这样我们就通过二分能在 $O(\log{n})$ 的时间复杂度内完成拼接,每次拼接的时候要完成一次运算,也就是说在 $O(n\log{n})$ 的时间复杂度得到了 $FWT[A]$ 。 接下来就是反演了,其实反演是很简单的,既然知道了 $A_0$ 的本身的子集是他自己 ( $A_0 = FAT[A_0]$ ), $A_1$ 的子集是 $FAT[A_0] + FAT[A_1](A_1'= A_0' + A_1'$ ),那就很简单的得出反演的递推式了: Loading Loading @@ -88,7 +84,7 @@ $$ 公式如下: $A[i] = \sum_{C_1}A[j] - \sum_{C_2}A[j]$ ( $C_1$ 表示 $i \And j$ 奇偶性为 $0$ , $C_2$ 表示 $i \And j$ 的奇偶性为 $1$ ) $A_{i} = \sum_{C_1}A_{j} - \sum_{C_2}A_{j}$ ( $C_1$ 表示 $i \And j$ 奇偶性为 $0$ , $C_2$ 表示 $i \And j$ 的奇偶性为 $1$ ) 结论: Loading @@ -104,7 +100,7 @@ $$ 类比异或运算给出公式: $A[i] = \sum_{C_1}A[j] - \sum_{C_2}A[j]$ ( $C_1$ 表示 $i|j$ 奇偶性为 $0$ , $C_2$ 表示 $i|j$ 的奇偶性为 $1$ ) $A_{i} = \sum_{C_1}A_{j} - \sum_{C_2}A_{j}$ ( $C_1$ 表示 $i|j$ 奇偶性为 $0$ , $C_2$ 表示 $i|j$ 的奇偶性为 $1$ ) $$ FWT[A] = merge(FWT[A_1] - FWT[A_0], FWT[A_1] + FWT[A_0]) Loading docs/math/poly.md→docs/math/poly/intro.md +13 −14 Original line number Diff line number Diff line Loading @@ -2,22 +2,22 @@ ### 多项式的度 对于一个多项式 $f\left(x\right)$,称其最高次项的次数为该多项式的**度(Degree)**,记作 $\operatorname{deg}{f}$. 对于一个多项式 $f\left(x\right)$,称其最高次项的次数为该多项式的**度(Degree)**,记作 $\operatorname{deg}{f}$。 ### 多项式的逆元 对于多项式 $f\left(x\right)$,若存在 $g\left(x\right)$ 满足: 对于多项式 $f\left(x\right)$,若存在 $g\left(x\right)$ 满足: $$ \begin{aligned} f\left(x\right)g\left(x\right)&\equiv 1\pmod{x^{n}}\\ \operatorname{deg}{g}&\leqslant\operatorname{deg}{f} \end{aligned} $$ 则称 $g\left(x\right)$ 为 $f\left(x\right)$ 在模 $x^{n}$ 意义下的**逆元(Inverse Element)**,记作 $f^{-1}\left(x\right)$. 则称 $g\left(x\right)$ 为 $f\left(x\right)$ 在模 $x^{n}$ 意义下的**逆元(Inverse Element)**,记作 $f^{-1}\left(x\right)$。 ### 多项式的余数和商 对于多项式 $f\left(x\right),g\left(x\right)$,存在**唯一**的 $Q\left(x\right),R\left(x\right)$ 满足: 对于多项式 $f\left(x\right),g\left(x\right)$,存在**唯一**的 $Q\left(x\right),R\left(x\right)$ 满足: $$ \begin{aligned} f\left(x\right)&=Q\left(x\right)g\left(x\right)+R\left(x\right)\\ Loading @@ -33,7 +33,7 @@ $$f\left(x\right)\equiv R\left(x\right)\pmod{g\left(x\right)}$$ ### <span id="ln-exp">多项式的对数函数与指数函数</span> 对于一个多项式 $f\left(x\right)$,可以将其对数函数看作其与麦克劳林级数的复合: 对于一个多项式 $f\left(x\right)$,可以将其对数函数看作其与麦克劳林级数的复合: $$\ln{\left(1-f\left(x\right)\right)}=-\sum_{i=1}^{+\infty}\frac{f^{i}\left(x\right)}{i}$$ Loading @@ -43,7 +43,7 @@ $$\exp{f\left(x\right)}=e^{f\left(x\right)}=\sum_{i=0}^{+\infty}\frac{f^{i}\left ### 多项式的多点求值和插值 **多项式的多点求值(Multi-point evaluation)** 即给出一个多项式 $f\left(x\right)$ 和 $n$ 个点 $x_{1},x_{2},...,x_{n}$,求 **多项式的多点求值(Multi-point evaluation)** 即给出一个多项式 $f\left(x\right)$ 和 $n$ 个点 $x_{1},x_{2},...,x_{n}$,求 $$f\left(x_{1}\right),f\left(x_{2}\right),...,f\left(x_{n}\right) $$ Loading @@ -53,11 +53,10 @@ $$\left(x_{0},y_{0}\right),\left(x_{1},y_{1}\right),...,\left(x_{n},y_{n}\right) 求一个 $n$ 次多项式 $f\left(x\right)$ 使得这 $n+1$ 个点都在 $f\left(x\right)$ 上. 这两种操作的实质就是将多项式在**系数表示**和**点值表示**间转化. 这两种操作的实质就是将多项式在**系数表示**和**点值表示**间转化。 ## References [**Picks's Blog**](https://picks.logdown.com) [**Miskcoo's Space**](https://blog.miskcoo.com) Loading
docs/math/poly-div-mod.mddeleted 100755 → 0 +0 −130 Original line number Diff line number Diff line ## Description 给定多项式 $f\left(x\right),g\left(x\right)$,求 $g\left(x\right)$ 除 $f\left(x\right)$ 的商 $Q\left(x\right)$ 和余数 $R\left(x\right)$. ## Method 发现若能消除 $R\left(x\right)$ 的影响则可直接[**多项式求逆**](../poly-inv)解决. 考虑构造变换 $$f^{R}\left(x\right)=x^{\operatorname{deg}{f}}f\left(\frac{1}{x}\right)$$ 观察可知其实质为反转 $f\left(x\right)$ 的系数. 设 $n=\operatorname{deg}{f},m=\operatorname{deg}{g}$. 将 $f\left(x\right)=Q\left(x\right)g\left(x\right)+R\left(x\right)$ 中的 $x$ 替换成 $\frac{1}{x}$ 并将其两边都乘上 $x^{n}$,得到: $$\begin{aligned} f\left(\frac{1}{x}\right)&=x^{n-m}Q\left(x\right)x^{m}g\left(x\right)+x^{n-m+1}x^{m-1}R\left(x\right)\\ f^{R}\left(x\right)&=Q^{R}\left(x\right)g^{R}\left(x\right)+x^{n-m+1}R^{R}\left(x\right) \end{aligned}$$ 注意到上式中 $R^{R}\left(x\right)$ 的系数为 $x^{n-m+1}$,则将其放到模 $x^{n-m+1}$ 意义下即可消除 $R^{R}\left(x\right)$ 带来的影响. 又因 $Q^{R}\left(x\right)$ 的次数为 $\left(n-m\right)<\left(n-m+1\right)$,故 $Q^{R}\left(x\right)$ 不会受到影响. 则: $$f^{R}\left(x\right)\equiv Q^{R}\left(x\right)g^{R}\left(x\right)\pmod{x^{n-m+1}}$$ 使用多项式求逆即可求出 $Q\left(x\right)$,将其反代即可得到 $R\left(x\right)$. 时间复杂度 $O\left(n\log{n}\right)$. ## Code ??? " `poly-div-mod.cpp` " ```cpp using Z=int; using mZ=long long; using poly_t=Z[mxdg]; using poly=Z*const; inline int calcpw2(const int&n){ int t=1; for(;t<n;t<<=1); return t; } inline void cp(const Z*const&sl,const Z*const&sr,Z*const&dl,Z*const&dr){ std::copy(sl,sr,dl); if(sr-sl<dr-dl) std::fill(dl+(sr-sl),dr,0); } void polydiv(const poly&f,const int&n,const poly&g,const int&m,poly&Q,poly&R){ static poly_t div_t; const int res=n-m+1; const int deg1=calcpw2(res+res); std::reverse_copy(g,g+m,Q); if(m<deg1) std::fill(Q+m,Q+deg1,0); polyinv(Q,div_t,res); std::reverse_copy(f+m-1,f+n,Q); std::fill(Q+res,Q+deg1,0); DFT(Q,deg1);DFT(div_t,deg1); for(int i=0;i!=deg1;++i) Q[i]=(mZ)Q[i]*div_t[i]%p; IDFT(Q,deg1); std::reverse(Q,Q+res); std::fill(Q+res,Q+deg1,0); const int deg2=calcpw2(n); cp(Q,Q+res,R,R+deg2); cp(g,g+m,div_t,div_t+deg2); DFT(R,deg2);DFT(div_t,deg2); for(int i=0;i!=deg2;++i) R[i]=(mZ)R[i]*div_t[i]%p; IDFT(R,deg2); for(int i=0;i!=m;++i) R[i]=sub(f[i],R[i]); std::fill(R+m-1,R+deg2,0); } void polymod(const poly&f,const int&n,const poly&g,const int&m,poly&R){ static poly_t mod_t; const int res=n-m+1; const int deg1=calcpw2(res+res); std::reverse_copy(g,g+m,R); if(m<deg1) std::fill(R+m,R+deg1,0); polyinv(R,mod_t,res); std::reverse_copy(f+m-1,f+n,R); std::fill(R+res,R+deg1,0); DFT(R,deg1);DFT(mod_t,deg1); for(int i=0;i!=deg1;++i) R[i]=(mZ)R[i]*mod_t[i]%p; IDFT(R,deg1); std::reverse(R,R+res); std::fill(R+res,R+deg1,0); const int deg2=calcpw2(n); cp(g,g+m,mod_t,mod_t+deg2); DFT(R,deg2);DFT(mod_t,deg2); for(int i=0;i!=deg2;++i) R[i]=(mZ)R[i]*mod_t[i]%p; IDFT(R,deg2); for(int i=0;i!=m;++i) R[i]=sub(f[i],R[i]); std::fill(R+m-1,R+deg2,0); } ```
docs/math/poly/div-mod.md 0 → 100755 +34 −0 Original line number Diff line number Diff line ## Description 给定多项式 $f\left(x\right),g\left(x\right)$,求 $g\left(x\right)$ 除 $f\left(x\right)$ 的商 $Q\left(x\right)$ 和余数 $R\left(x\right)$。 ## Method 发现若能消除 $R\left(x\right)$ 的影响则可直接[**多项式求逆**](../poly-inv)解决. 考虑构造变换 $$f^{R}\left(x\right)=x^{\operatorname{deg}{f}}f\left(\frac{1}{x}\right) $$ 观察可知其实质为反转 $f\left(x\right)$ 的系数。 设 $n=\operatorname{deg}{f},m=\operatorname{deg}{g}$。 将 $f\left(x\right)=Q\left(x\right)g\left(x\right)+R\left(x\right)$ 中的 $x$ 替换成 $\frac{1}{x}$ 并将其两边都乘上 $x^{n}$,得到: $$ \begin{aligned} f\left(\frac{1}{x}\right)&=x^{n-m}Q\left(x\right)x^{m}g\left(x\right)+x^{n-m+1}x^{m-1}R\left(x\right)\\ f^{R}\left(x\right)&=Q^{R}\left(x\right)g^{R}\left(x\right)+x^{n-m+1}R^{R}\left(x\right) \end{aligned} $$ 注意到上式中 $R^{R}\left(x\right)$ 的系数为 $x^{n-m+1}$,则将其放到模 $x^{n-m+1}$ 意义下即可消除 $R^{R}\left(x\right)$ 带来的影响。 又因 $Q^{R}\left(x\right)$ 的次数为 $\left(n-m\right)<\left(n-m+1\right)$,故 $Q^{R}\left(x\right)$ 不会受到影响。 则: $$f^{R}\left(x\right)\equiv Q^{R}\left(x\right)g^{R}\left(x\right)\pmod{x^{n-m+1}}$$ 使用多项式求逆即可求出 $Q\left(x\right)$,将其反代即可得到 $R\left(x\right)$。 时间复杂度 $O\left(n\log{n}\right)$。
docs/math/fft.md→docs/math/poly/fft.md +24 −24 Original line number Diff line number Diff line (本页面部分内容转载自[桃酱的算法笔记](https://zhuanlan.zhihu.com/c_1005817911142838272),原文戳[链接](https://zhuanlan.zhihu.com/p/41867199),已获得作者授权) 一直想学 FFT,之前牛客的多小有一道组合数学就用 FFT 写的,而且当时还傻乎乎的用唯一分解定理,但是自己好久没静下心学什么了,而且自己的数学功底又不好,导致一直学不会。看了很多人的博客也没看明白,尤其是原根。在我看了几十篇博客之后终于看懂了……所以想写一篇能够让大多数人都看得懂的教程。花费时间 3 天终于写完啦~~~~\~~ 一直想学 FFT,之前牛客的多校有一道组合数学就用 FFT 写的,而且当时还傻乎乎的用唯一分解定理,但是自己好久没静下心学什么了,而且自己的数学功底又不好,导致一直学不会。看了很多人的博客也没看明白,尤其是原根。在我看了几十篇博客之后终于看懂了……所以想写一篇能够让大多数人都看得懂的教程。花费时间 3 天终于写完啦~~~~\~~ 另外,本文 FFT 部分的代码实现全部参考 kuangbin 的模板(2018.7 更新)资源地址如下 Loading Loading @@ -100,7 +100,7 @@ $$ 。另外, $i$ 对于虚数的意义,与 $1$ 对于实数的意义是一样的。如果我说得不够明确,你可以看下面我引用的百科说明。 > 在数学中,虚数就是形如 $a+b \times i$ 的数,其中 $a,b$ 是实数,且 $b \neq 0$ , $i^2 = - 1$ 。虚数这个名词是 17 世纪著名数学家笛卡尔创立,因为当时的观念认为这是真实不存在的数字。后来发现虚数 $a+b \times i$ 的实部 $a$ 可对应平面上的横轴,虚部 $b$ 与对应平面上的纵轴,这样虚数 $a+b \times i$ 可与平面内的点 $(a,b)$ 对应。 > 在数学中,虚数就是形如 $a+b \times i$ 的数,其中 $a,b$ 是实数,且 $b \neq 0$ , $i^2 = - 1$ 。虚数这个名词是 17 世纪著名数学家笛卡尔创立,因为当时的观念认为这是真实不存在的数字。后来发现虚数 $a+b \times i$ 的实部 $a$ 可对应平面上的横轴,虚部 $b$ 与对应平面上的纵轴,这样虚数 $a+b \times i$ 可与平面内的点 $(a,b)$ 对应。 > > 可以将虚数 $bi$ 添加到实数 $a$ 以形成形式 $a + bi$ 的复数,其中实数 $a$ 和 $b$ 分别被称为复数的实部和虚部。一些作者使用术语纯虚数来表示所谓的虚数,虚数表示具有非零虚部的任何复数。——百度百科 Loading Loading @@ -160,7 +160,7 @@ $$ (因为他的角度是相当于单位角度),就能知道 $\omega_4^0, \omega_4^1, \omega_4^2, \omega_4^3$ 了呢?当然是这样的…… $\omega_4^0$ 恒等于 $1$ , $\omega_4^2$ 的角度是 $\omega_4^0$ 的两倍,所以 $\omega_4^2 = (\omega_4^1)^2 = i^2=-1$ , 依次以此类推。 $\omega_4^0$ 恒等于 $1$ , $\omega_4^2$ 的角度是 $\omega_4^0$ 的两倍,所以 $\omega_4^2 = (\omega_4^1)^2 = i^2=-1$ , 依次以此类推。 因此,我们只要知道 $\omega_k^1$ ,就能求出 $\omega_k^n$ 。所以我们把 $\omega_k^1$ 称为单位复根,简写为 $\omega_k$ Loading Loading @@ -216,13 +216,13 @@ $$ !前方高能: 这个函数能处理的多项式长度只能是 $2^m(m \in N^ \times )$ , 否则在分治的时候左右不一样长,右边取不到系数了,程序没法进行。所以要在第一次 DFT 之前就把序列向上补成长度为 $2^m(m \in N^ \times )$ (高次系数补 $0$ )、最高项次数为 $n-1$ 的多项式。一定要预处理哦 这个函数能处理的多项式长度只能是 $2^m(m \in N^ \times )$ , 否则在分治的时候左右不一样长,右边取不到系数了,程序没法进行。所以要在第一次 DFT 之前就把序列向上补成长度为 $2^m(m \in N^ \times )$ (高次系数补 $0$ )、最高项次数为 $n-1$ 的多项式。一定要预处理哦 然后我在代入值的时候,因为要代入 $n$ 个不同值,所以我们就代入 $\omega_n^0,\omega_n^1,\omega_n^2,\cdots, \omega_n^{n-1} (n=2^m(m \in N^ \times ))$ 一共 $2^m$ 个不同值。 ```c++ ```cpp /* * 做 FFT *len 必须是 2^k 形式 Loading Loading @@ -260,7 +260,7 @@ void fft(Complex y[], int len, int on) { 这里附上代码 ```c++ ```cpp /* * 进行 FFT 和 IFFT 前的反置变换 * 位置 i 和 i 的二进制反转后的位置互换 Loading Loading @@ -333,7 +333,7 @@ $$ 记 $S\left(\omega_n^a\right)=\sum_{i=0}^{n-1}\left(\omega_n^a\right)^i$。 当 $a=0$ 时,$S\left(\omega_n^a\right)=n$. 当 $a=0$ 时,$S\left(\omega_n^a\right)=n$。 当 $a\neq 0$ 时,我们错位相减一下 Loading Loading @@ -371,7 +371,7 @@ $$ 所以我们 fft 函数可以集 DFT 和 IDFT 于一身。见下 ```c++ ```cpp /* * 做 FFT *len 必须是 2^k 形式 Loading Loading @@ -405,7 +405,7 @@ void fft(Complex y[], int len, int on) { 好了现在附上全部代码([HDU 1402](http://acm.hdu.edu.cn/showproblem.php?pid=1402)),序言说过代码来自 kuangbin 的模板~~~~~ ```c++ ```cpp #include <cmath> #include <cstdio> #include <cstring> Loading
docs/math/fwt.md→docs/math/poly/fwt.md +11 −15 Original line number Diff line number Diff line Loading @@ -6,23 +6,19 @@ 其实这个变换在信号处理中应用很广泛,fft 是 double 类型的,但是 walsh 把信号在不同震荡频率方波下拆解,因此所有的系数都是绝对值大小相同的整数,这使得不需要作浮点数的乘法运算,提高了运算速度。 所以,FWT 和 FFT 的核心思想应该是相同的。都是对数组的变换。我们设数组 $A$ 经过快速沃尔什变换之后记作 $FWT[A]$ . 所以,FWT 和 FFT 的核心思想应该是相同的,都是对数组的变换。我们记对数组 $A$ 进行快速沃尔什变换后得到的结果为 $FWT[A]$ 。 那么 FWT 核心思想就是: 我们需要一个新序列 $C$ ,由序列 $A$ 和序列 $B$ 经过某运算规则得到,即 $C = A \cdot B$ 我们需要一个新序列 $C$ ,由序列 $A$ 和序列 $B$ 经过某运算规则得到,即 $C = A \cdot B$ ; 我们先正向得到 $FWT[A], FWT[B]$ 我们先正向得到 $FWT[A], FWT[B]$,再根据 $FWT[C]=FWT[A] \cdot FWT[B]$ 在 $O(n)$ 的时间复杂度内求出 $FWT[C]$ ; 然后根据 $FWT[C]=FWT[A] \cdot FWT[B]$ 在 $O(n)$ 求出 $FWT[C]$ 然后逆向想运算得到原序列 $C$ 。时间复杂度为 $O(nlogn)$ 然后逆向运算得到原序列 $C$ 。时间复杂度为 $O(n \log{n})$。 在算法竞赛中,FWT 是用于解决对下标进行位运算卷积问题的方法。 公式: $C[i] = \sum_{i=j \bigoplus k}A[j] * B[k]$ 公式: $C_{i} = \sum_{i=j \bigoplus k}A_{j} B_{k}$ (其中 $\bigoplus$ 是二元位运算中的某一种, $*$ 是普通乘法) Loading @@ -38,9 +34,9 @@ 现在要得到 $FWT[C] = FWT[A] * FWT[B]$ ,我们就要构造这个 fwt 的规则。 我们按照定义,显然可以构造 $FWT[A] = A' = \sum_{i=i|j}A[j]$ ,来表示 $j$ 满足二进制中 $1$ 为 $i$ 的子集。 我们按照定义,显然可以构造 $FWT[A] = A' = \sum_{i=i|j}A_{j}$ ,来表示 $j$ 满足二进制中 $1$ 为 $i$ 的子集。 那么显然会有 $C[i] = \sum_{i=j|k}A[j]*B[k] \Rightarrow FWT[C] = FWT[A] * FWT[B]$ 那么显然会有 $C_{i} = \sum_{i=j|k}A_{j}*B_{k} \Rightarrow FWT[C] = FWT[A] * FWT[B]$ 那么我们接下来看 $FWT[A]$ 怎么求。 Loading @@ -56,7 +52,7 @@ $$ 其中 merge 表示像字符串拼接一样把它们拼起来, $+$ 就是普通加法,表示对应二进制位相加。 这样我们就通过二分能在 $O(logn)$ 完成拼接,每次拼接的时候要完成一次运算,也就是说在 $O(nlogn)$ 的时间复杂度得到了 $FWT[A]$ 。 这样我们就通过二分能在 $O(\log{n})$ 的时间复杂度内完成拼接,每次拼接的时候要完成一次运算,也就是说在 $O(n\log{n})$ 的时间复杂度得到了 $FWT[A]$ 。 接下来就是反演了,其实反演是很简单的,既然知道了 $A_0$ 的本身的子集是他自己 ( $A_0 = FAT[A_0]$ ), $A_1$ 的子集是 $FAT[A_0] + FAT[A_1](A_1'= A_0' + A_1'$ ),那就很简单的得出反演的递推式了: Loading Loading @@ -88,7 +84,7 @@ $$ 公式如下: $A[i] = \sum_{C_1}A[j] - \sum_{C_2}A[j]$ ( $C_1$ 表示 $i \And j$ 奇偶性为 $0$ , $C_2$ 表示 $i \And j$ 的奇偶性为 $1$ ) $A_{i} = \sum_{C_1}A_{j} - \sum_{C_2}A_{j}$ ( $C_1$ 表示 $i \And j$ 奇偶性为 $0$ , $C_2$ 表示 $i \And j$ 的奇偶性为 $1$ ) 结论: Loading @@ -104,7 +100,7 @@ $$ 类比异或运算给出公式: $A[i] = \sum_{C_1}A[j] - \sum_{C_2}A[j]$ ( $C_1$ 表示 $i|j$ 奇偶性为 $0$ , $C_2$ 表示 $i|j$ 的奇偶性为 $1$ ) $A_{i} = \sum_{C_1}A_{j} - \sum_{C_2}A_{j}$ ( $C_1$ 表示 $i|j$ 奇偶性为 $0$ , $C_2$ 表示 $i|j$ 的奇偶性为 $1$ ) $$ FWT[A] = merge(FWT[A_1] - FWT[A_0], FWT[A_1] + FWT[A_0]) Loading
docs/math/poly.md→docs/math/poly/intro.md +13 −14 Original line number Diff line number Diff line Loading @@ -2,22 +2,22 @@ ### 多项式的度 对于一个多项式 $f\left(x\right)$,称其最高次项的次数为该多项式的**度(Degree)**,记作 $\operatorname{deg}{f}$. 对于一个多项式 $f\left(x\right)$,称其最高次项的次数为该多项式的**度(Degree)**,记作 $\operatorname{deg}{f}$。 ### 多项式的逆元 对于多项式 $f\left(x\right)$,若存在 $g\left(x\right)$ 满足: 对于多项式 $f\left(x\right)$,若存在 $g\left(x\right)$ 满足: $$ \begin{aligned} f\left(x\right)g\left(x\right)&\equiv 1\pmod{x^{n}}\\ \operatorname{deg}{g}&\leqslant\operatorname{deg}{f} \end{aligned} $$ 则称 $g\left(x\right)$ 为 $f\left(x\right)$ 在模 $x^{n}$ 意义下的**逆元(Inverse Element)**,记作 $f^{-1}\left(x\right)$. 则称 $g\left(x\right)$ 为 $f\left(x\right)$ 在模 $x^{n}$ 意义下的**逆元(Inverse Element)**,记作 $f^{-1}\left(x\right)$。 ### 多项式的余数和商 对于多项式 $f\left(x\right),g\left(x\right)$,存在**唯一**的 $Q\left(x\right),R\left(x\right)$ 满足: 对于多项式 $f\left(x\right),g\left(x\right)$,存在**唯一**的 $Q\left(x\right),R\left(x\right)$ 满足: $$ \begin{aligned} f\left(x\right)&=Q\left(x\right)g\left(x\right)+R\left(x\right)\\ Loading @@ -33,7 +33,7 @@ $$f\left(x\right)\equiv R\left(x\right)\pmod{g\left(x\right)}$$ ### <span id="ln-exp">多项式的对数函数与指数函数</span> 对于一个多项式 $f\left(x\right)$,可以将其对数函数看作其与麦克劳林级数的复合: 对于一个多项式 $f\left(x\right)$,可以将其对数函数看作其与麦克劳林级数的复合: $$\ln{\left(1-f\left(x\right)\right)}=-\sum_{i=1}^{+\infty}\frac{f^{i}\left(x\right)}{i}$$ Loading @@ -43,7 +43,7 @@ $$\exp{f\left(x\right)}=e^{f\left(x\right)}=\sum_{i=0}^{+\infty}\frac{f^{i}\left ### 多项式的多点求值和插值 **多项式的多点求值(Multi-point evaluation)** 即给出一个多项式 $f\left(x\right)$ 和 $n$ 个点 $x_{1},x_{2},...,x_{n}$,求 **多项式的多点求值(Multi-point evaluation)** 即给出一个多项式 $f\left(x\right)$ 和 $n$ 个点 $x_{1},x_{2},...,x_{n}$,求 $$f\left(x_{1}\right),f\left(x_{2}\right),...,f\left(x_{n}\right) $$ Loading @@ -53,11 +53,10 @@ $$\left(x_{0},y_{0}\right),\left(x_{1},y_{1}\right),...,\left(x_{n},y_{n}\right) 求一个 $n$ 次多项式 $f\left(x\right)$ 使得这 $n+1$ 个点都在 $f\left(x\right)$ 上. 这两种操作的实质就是将多项式在**系数表示**和**点值表示**间转化. 这两种操作的实质就是将多项式在**系数表示**和**点值表示**间转化。 ## References [**Picks's Blog**](https://picks.logdown.com) [**Miskcoo's Space**](https://blog.miskcoo.com)