现有一个线性同余方程\(ax≡1(\bmod \ p)\),
则称\(x\)为\(a\)在模\(p\)意义下的逆元。
那么如何求逆元呢?
我们先求简单一点的情况,
求单个数的逆元。
此方程\(ax≡1(\bmod \ p)\)等价于求满足\(ax+py=1\),
的解。
显然,
\((a,p)=1\)是此方程有解的充分必要条件。
接下来介绍扩展欧几里得算法来求逆元。
扩欧
此方程化为
将1变换一下可以得到
注意到
因此原式又可以化为
去括号展开一下
观察一下两个方程的系数
便可以得到一个惊人的结论,
我们在求解方程\(ay_0+px_0=1\)的时候,
得到的\(x_0,y_0\)可以推出方程\(ax+py=1\)的\(x,y\),
也就是说,
我们可以通过计算\(x_0,y_0\)来得到\(x,y\)。
然后有注意到,
我们这样子计算下去,
类似于欧几里得求最大公约数的过程,
最终我们会使得\(p\)变成0,
此时的方程为
可以得到\(x=1,y=0\)的一组解,
然后可以一直往上求解出\(x,y\)的值。
由于欧几里得算法求最大公约数的时间复杂度为\(O(\log n)\),
所以扩展欧几里得算法的时间复杂度也是\(O(\log n)\)。
这样我们便求解出了单个数的逆元。
费马小定理
费马小定理描述如下
证明读者自行查阅资料。
有了这个定理,
求解逆元便很简单了。
将费马小定理的式子变一下形可以得到
观察可知\(a^{p-2}\)就是\(a\)在模\(p\)意义下的逆元,
求解方法考虑使用快速幂。
时间复杂度\(O(\log p)\)。
欧拉定理
欧拉定理描述如下,
首先定义,
表示\([1,n]\)以内与\(n\)互素的数的个数,
那么欧拉定理,
两边同时乘以\(a^{-1}\)可以得到,
那么我们就找到了求解逆元的另一种方式,
时间复杂度根据欧拉函数的求解方式计算,
时间复杂度在\(O(\sqrt p)\sim O(\log p)\)不等。
当然,这个不用考虑\(p\)是不是素数的情况。
线性求逆元
刚才讨论到的都只能求单个的逆元,
可是求多个的逆元时时间复杂度又很高,
这时候我们可以使用线性求逆元。
线性求逆元可以解决求\(1\sim n\)的逆元。
我们要求解
首先
这是很显然的。
我们将原式变一下形,
两边同时乘上\(i^{-1}\times (p\bmod i)^{-1}\)可以得到
由于\(p \bmod i <i\),
所以我们求解\(i\)的逆元时,
可以利用前面求解过的逆元来求解\(i^{-1}\),
这样我们就做到了线性求解逆元,
时间复杂度\(O(n)\)。
阶乘求逆元
我们求出
也就是
记为
那么
在记
表示\(i\)的逆元,
那么,
这里\(0!=1\)
这样我们就完成了\(O(n+\log p)\)接近线性求逆元了。
前缀积求逆元
上面的线性求逆元只能求出\(1\sim n\)的逆元,而前缀积求逆元可以求出任意\(n\)个数的逆元。具体如下,现在要求求出\(a_i,(1≤i≤n)\)的逆元。
令
求出
定义
表示\(a_i\)的逆元
那么
因此我们可以先处理出\(f(n)^{-1}\),
然后,
根据上面的递推公式可以得到\(inv_i\)。这样的时间复杂度为\(O(n+\log \ p )\)。适用性很强。
线性筛
还是求解\([1,n]\)的逆元。
我们现将所有\(Prime∈[1,n]\)用线性筛求解出来,
然后对于每一个数\(i∈[1,n]\),
\(mpf(i)\)表示\(i\)的最小质因数,
我们现将所有的素数的逆元求解出来,
然后将每一个数的逆元通过前面计算过的计算出来,
因为\(\frac{i}{mpf(i)}\)是肯定是前面已经计算过的,
这里的时间复杂度大约为
。
浙公网安备 33010602011771号