题记: 逆元素是指可以取消另一给定元素运算的元素, 本文中主要谈及与算法竞赛的逆元.
在下才疏学浅, 如有纰缪和遗漏还望指出.
逆元
前置知识: 代数系统, 幺元.
逆元(Inverse element)的定义: 在代数系统<S, *>中, 若存在元素a,b ∈ S 且 a * b = 幺元e, 则元素a称为b的左逆元, 元素b称为a的右逆元. 若元素x同时为另一个元素y的左逆元和右逆元则称x是y的逆元. 同理y亦是x的逆元.
逆元的用处:
算法竞赛中经常会出现模余运算, 模余的加丶减丶乘法比较简单: a+b(mod p) = (a+b) mod p
a-b(mod p) = (a-b+p) mod p
a*b(mod p) = a * b mod p -- 考虑*的优先级高于%故没加()
但是对于模余除没接触过逆元的同学就莫名慌张了,除法会不会出现问题呢? 举个栗子: 最简单的C(n, 3) 即 n(n-1)(n-2) / 6 初学者的想法可能是先将n(n-1)(n-2)的模余乘法结果S算出来再除6但我们知道模余后S不一定会被6整除(这里一定出现的差错~), 那么怎么办呢? 于是聪明的人类发现了逆元这个东西. 先介绍性质: 在模余自然数域中, 除一个数等于乘以它的乘法逆元. 好! 这就是逆元的最原始用处. (但是你说是就是, 快给个证明xD)好, 那么证明如下:
如果 b*a = 1(mod p)
则 b = a^(-1) -- b是a的逆元
则 c / a = c * a^(-1) = c * b (mod p)
于是上述性质得到了证明。
求逆元的方法: 求解逆元主要有两种方式,扩展欧几里得算法以及基于费马小定理的快速幂算法。
费马小定理
定理:假如p是质数,且gcd(a,p)=1,那么 a^(p-1)≡1(mod p)
于是容易得到 a* a^(p-2)≡1(mod p)故 a^(p-2)为a在mod p下的逆元
typedef long long ll;
const ll mod = p;
//快速幂 求x的n次幂
ll mod_pow(ll x, ll n){
ll res = 1; // result
while(n){
if(n&1) res = res*x%mod;
x = x*x%mod; n>>=1;
}
return res;
}
//求x在mod p下的逆元
ll mod_reverse(ll x){
return mod_pow(x, mod-2);
}
ps:在一般情况下,如果快速幂中n过大,可以将n%φ(mod)来达到降幂 --不理解请参考欧拉定理
扩展欧几里得
想法是ax+by=gcd(x,y) 若 x*(x^-1) mod p = 1 可以写成 x*a= p*b+1那么 x*a-p(y)*b=1就是说可以套用扩展欧几里得来求出a,b。 a即为x在mod p下的逆元
long long exgcd(long long a,long long b,long long &x,long long &y)
{
if (b==0) { x=1,y=0; return a; }
long long d=exgcd(b,a%b,x,y);
long long tmp=x;
x=y;
y=tmp-a/b*y;
return d;
}
//求x在mod p的逆元
long long mod_reverse(ll x){
long long a, b;
long long g = exgcd(x, p, a, b);
return (a/g%p+p)%p;
}
关于逆元的预处理, 逆元可以在O(n)的时间复杂度预处理, 如果已经处理出阶乘表可以在O(1)的时间内求解,对于未进行任何预处理的逆元可以在(plogp+N^(-1/2))的时间内及逆行求解p代表的是逆元中不同质数的个数。
逆元的预处理
typedef long long ll;
const ll mod = ?;
ll r[MAX_N];
void init(){
r[1] = 1;
for(int i=2; i<MAX_N; i++) r[i] = r[mod%i] * (mod-mod/i)%mod;
}
证明:
p是模数,i是待求的逆元,我们求的是i−1i−1在mod p意义下的值
p=k∗i+rp=k∗i+r令 r < i,则k=p/i,r=p%i
k∗i+r≡0(modp)k∗i+r≡0(mod p)
k∗r−1+i−1≡0(mod p)k∗r−1+i−1≡0(mod p)
i−1≡−k∗r−1(mod p)i−1≡−k∗r−1(mod p)
i−1≡−p/i∗inv[p mod i]i−1≡−p/i∗inv[p mod i]
说白了就是:inv[i]=-(mod/i)*inv[i%mod]
未完待续