目录
文章过长的下场……
- 前置技能:复数
- 前置技能:原根
- 前置技能:快速多项式乘法(FFT&NTT)
- 前置技能:导数
- 泰勒展开
- 牛顿迭代
- 多项式逆元
- 多项式取模
与内容无关的前置技能的前置技能之一:复数……
复数是定义在二维平面中的数。
两种表示方法:
a+bi,er+θi
(e是自然对数,i2=−1(即虚数单位))
第一种是把a看成x轴座标,b看成y轴座标。
第二种是看成一条长度为er的线段被绕着原点旋转。
用欧拉公式解释第二种表达方式:
eθi=cosθ+isinθ
证明后面会讲。
两个复数相乘,相除用er+θi可以很清晰的看出是角度相加/减,长度相乘/除。
与内容无关的前置技能的前置技能之二:原根……
费马小定理:对于质数p,有ap−1≡1(modp)
p的原根是从一到p-1次幂在模p意义下都不一样的数(刚好p-1次幂模p才为1的数)。
现在有一个数a,而且ak≡1(modp)(k不是ϕ(p)的倍数,那么agcd(k,ϕ(p))≡1(modp)
所以只要判断ϕ(p)除以其任何一个质因数并判断这个数作为a的幂能不能到一,能的话a就不是原根。
前置技能:快速多项式乘法(FFT&NTT)
对于两个多项式求卷积,不考虑直接相乘,而是考虑转化成点值然后相乘再插值回来。
在复数空间内画个单位圆,并从中选出2k(k∈N)个点pi,使得p0=(1,0),pi=p1i,p0=p12k(1<i<2k)
(其实就是把这个圆2k等分,取每个扇形逆时针方向靠前的边)
(p0=(1,0)是复数空间上的乘法单位元)
现在要求这些pi。
对于一个多项式A,把它的x的奇数次的项和偶数次的项拆开,写成两个新多项式。
A(x)=a0+a1×x+a2×x2+⋯
A(x)=(a0+a2×x2+a4×x4+⋯)+x×(a1+a3×x2+a5×x4+⋯)
A(x)=A0(x2)+x×A1(x2)
会发现pi2=p1i×2=p1i×2×p0=p12k+i×2=p1(2k−1+i)×2=pi+2k−12
就是pi和pi绕过半圈后的那个点平方后是一样的,所以n个x时,每个子函数只有2n个x2的值要带进去。
然后就是递归求关于(x2)的多项式。
递归log2n层,每层要求的值的个数之和是n,总复杂度O(nlog2n)
求出点值乘起来之后,把结果再当做一个多项式塞回去再做FFT,pi取pi的逆元,然后把丢出来的所有项除以2k。
不知道为什么这样就完成了对特定的一列数插值的工作。
关于NTT只是使用了模意义下的单位元,逆元和原根(aϕ(p)≡1(modp))。
前置技能:导数
就是变化量……
设f′(x)为f(x)的导数,那么:
f′(x)=Δxf(x+Δx)−f(x)
左导数就是Δx从负数趋近0,右导数就是Δx从正数部分趋近0。
f(x)在某点x0存在导数必须同时满足三个条件:
- f(x)在x0处有定义
- f(x)在x0附近连续
- f(x)的左导数和右导数相等。
对于一个函数f(x),下面用(f(x))′表示它的导数。
当且仅当f(x)=k×ex时,f(x)求导是函数本身。
常用导数:
(xn)′=nxn−1
Δx是一个无穷小量。把式子展开后,分子只有Δx的一次项和零次项是有用的。
(lnx)′=x1
指数函数和对数函数关于y=x对称。
(f(g(x))′=f′(g(x))×g′(x)
ΔxΔf=ΔgΔf×ΔxΔg
(ax)′=lna×ax
对于任意指数函数都可以把底换成e???的形式,然后用复合函数合并导数。
(logax)′=x×lna1
对数函数之间只是常数差别,可以通过换底公式把logex转化成logax。
(sinx)′=cosx,(cosx)′=−sinx
不会证。
泰勒展开
泰勒展开只是一个工具。
一些特殊的函数我们可以尝试用多项式去逼近。
一个标准的泰勒展开形式是这样的(x0是我们选定的一个值):
A(x)=i=0∑∞ai(x−x0)i
然而大多数时候会发现x0为0时是展开的最好选择……
下面以sinx为例。
sinx=i=0∑∞aixi
为了求a0的值,我们可以把x=0带入原式……
得到0=a0×1,a0=0
怎么求a1?对等式左右两边求导……
cosx=i=1∑∞iaixi−1
再把x=0带进去……
得到1=1!×a1×1,a1=1
再求导……
−sinx=i=2∑∞i(i−1)aixi−2
把x=0带入得到0=2!×a2×1,a2=0
会发现求导时出现的系数在算时能形成阶乘的形式,sin和cos之间也有明显的循环节
继续写下去就是这样了:
sinx=x−3!x3+5!x5−7!x7+⋯
会发现对于ex这个函数进行泰勒展开就比较奇怪,因为它求导后是它自己……
按照刚刚的方法会算出这种玩意:
ex=i=0∑∞i!xi
泰勒展开证明欧拉公式
把ex在x的为实数时的泰勒展开搬到虚数部分。
eix=1+ix−2!x2−3!ix3+4!x4+⋯
这时候把cos和sin的泰勒展开写出来:
cosx=1−2!x2+4!x4+⋯,sinx=x−3!x3+5!x5
于是就愉快地发现eix=cosx+isinx
牛顿迭代
一个待啃的通俗讲法
牛顿迭代只有在函数存在二阶导(导数的导数)时才比较正常。
大体思路是随便猜一个解,然后把解更新成对原函数在这个位置的切线的0点,如此反复。
现在对于一个多项式A(x),想求A(x)=0的解。
首先猜一个解x0,对多项式进行泰勒展开。(谁说只有特殊函数才要泰勒展开来着)
A(x)=A(x0)+A′(x0)(x−x0)+⋯
同样,和求切线一样,认为自己猜的这个答案很接近正确答案,那么后面的项(x−x0)k(k∈N)会衰减地很快,平方项都可以不用考虑。
A(x)≈A(x0)+A′(x0)(x−x0)=A(x0)+A′(x0)x−A′(x0)x0
x≈A′(x0)A′(x0)x0+A(x0)=x0−A′(x0)A(x0)
后面那个其实就是求切线0点……
多项式逆元
一个多项式模xn的意义可以看作只取x0到xn−1的项。
现在想对于A(x)求出他在模xn意义下的逆元B(x),即A(x)×B(x)≡1(modxn)
赵设:“搞不定它,先搞定它小弟……”
一个多项式模x的逆元显然就是常数项的逆元。
现在考虑知道A(x)在模x2n下的逆元B0(x),现在想要求出在xn下的逆元B(x)。
B(x)≡B0(x)(modx2n)
B(x)−B0(x)≡0(modx2n)
(B(x)−B0(x))2≡0(modxn)
(上一步是因为B(x)−B0(x)的前2n项都为零,最小的可能有值的项是x2n这项卷自己得到,大于等于xn)
B(x)2−2B(x)B0(x)+B0(x)2≡0(modxn)
两边同时与A(x)卷积
A(x)B(x)−2B0(x)+A(x)B0(x)2≡0(modxn)
B(x)≡2B0(x)−AB0(x)2
会发现A(x)在模xn+1意义下的逆元也是在模xn意义下的逆元,直接把逆元往大取再模xn就行。
多项式取模
留坑待填