在求解除法取模问题\((a \div b) \mod m\)时,我们可以转化为\([a \mod (b \times m)]\div b\)
但是如果\(b\)很大,则会出现爆精度问题,所以我们避免使用除法直接计算。
可以使用逆元将除法转换为乘法:假设\(b\)存在乘法逆元,即与\(m\)互质(充要条件)。
设\(c\)是\(b\)的逆元,即\(b \times c≡1(\mod m)\)
那么有\(a\div b=(a\div b)\times 1=(a\div b)\times b\times c=a\times c(\mod m)\)
即除以一个数取模等于乘以这个数的逆元取模
- 逆元求解一般利用扩欧。
- 当\(m\)为质数的时候直接使用费马小定理,\(m\)非质数使用欧拉函数。
- 当\(m\)为质数的时候,神奇的线性方法。
扩展欧几里得算法
要求\(a,m\)互素,存在唯一解。
int extgcd(int a, int b, int &x, int &y) {
int d=a;
if (b!=0) {
d=extgcd(b,a%b,y,x);
y-=(a/b)*x;
}
else {
x=1;
y=0;
}
return d;
}
int mod_inverse(int a, int m) {
int x, y;
extgcd(a, m, x, y);
return (m+x%m)%m;
}
费马小定理
在\(p\)是素数的情况下,对任意整数\(x\)都有\(x^{p}≡x(\mod p)\)。
如果\(x\)无法被\(p\)整除,则有\(x^{p}-1≡1(\mod p)\)。
可以在\(p\)为素数的情况下求出一个数的逆元,\(x \times x^{p}-2≡1(\mod p)\),\(x^{p}-2\)即为\(x\)的逆元。
LL mul(LL a, LL n) {//求a ^ n % mod
LL s=1;
while (n) {
if (n&1) s=s*a%mod;
a=a*a%mod;
n>>=1;
}
return s;
}
//mul(a, n-2);
欧拉函数
令\(\phi(m)\)表示小于等于\(m\)且与\(m\)互素的正整数的个数。
如果\(x\)和\(m\)互质,则有\(x\phi (m)≡1(\mod m)\),即\(x\times x\phi (m)-1≡1(\mod m)\),\(x^{\phi(m)-1}\)为\(x\)的逆元。
在\(m\)为质数的情况下,\(\phi (m)=m-1\),即为费马小定理。
思路:
求出欧拉函数的值,利用欧拉函数的积性性质:
对于任意整数\(n\),可以将它分解\(n=p_{k1} \times p_{k2} \times p_{k3} \times \cdots \times p_{km}\),其中\(p_{i}\)为质数,\(\phi(n)=\phi(p_{k1}) \times \phi(p_{k2})\times \cdots \phi(p_{km})\)
最后转化为\(\phi(n)=n \times \prod(p_{i}-1) \div p_{i}\)
对给定\(n\)进行整数分解,时间复杂度\(O(n)?\)。
int eurler_phi(int n) {
int res=n;
for (int i=2; i*i<=n; i++) {
if (n%i==0) {
res=res/i*(i-1);
while (n%i==0) n/=i;
}
}
if (n!=1) res=res/n*(n-1);
return res;
}
埃氏筛法求欧拉函数值的表,每次发现质因子就把他的倍数的欧拉函数乘上\((p-1)\times p\)。
当\(n\)为奇数时,有\(\phi(2\times n)=\phi(n)\)
因为\(2\times n\)是偶数,偶数与偶数一定不互素,所以只考虑\(2n\) 与小于它的奇数互素的情况,则恰好就等于\(n\)的欧拉函数值。
int euler[maxn];
void euler_phi2() {
for (int i=0; i<maxn; i++)
euler[i]=i;
for (int i=2; i<maxn; i++)
if (euler[i]==i)
for (int j=i; j<maxn; j+=i)
euler[j]=euler[j]/i*(i-1);
}
线性时间求所有逆元
规定\(p\)为质数,且\(1^{-1}≡1(\mod p)\)
设\(p=k\times a+b(b<a,1<a<p)\),即\(k\times a+b≡0(\mod p)\)
两边同时乘以\(a^{-1}\times b^{-1}\),得到
\(k\times b^{-1}+a^{-1}≡0(\mod p)\)
\(a^{-1}≡-k\times b-1(\mod p)\)
\(a^{-1}≡-p\div a×(p\mod a)^{-1}(\mod p)\)
从头开始扫一遍即可,时间复杂度\(O(n)\)。
int inv[maxn];
inv[1]=1;
for (int i=2; i<maxn; i++)
inv[i]=(p-p/i)%p*inv[p%i];
原文地址:https://www.cnblogs.com/shenxiaohuang/p/10162141.html