乘法逆元
在组合计数中,由于答案过大,需要取模。比如计算 C n m C_n^m Cnm.
为了求出 a b ≡ x ( m o d m ) \frac a b \equiv x (mod\ m) ba≡x(mod m)中的 x x x,就需要求出 b b b的逆元 b − 1 b^{-1} b−1,因为 b b − 1 ≡ 1 bb^{-1} \equiv 1 bb−1≡1,所以 a b ≡ a b − 1 \frac a b \equiv ab^{-1} ba≡ab−1。
1-费马小定理
(的推论) a p ≡ a ( m o d p ) a^p \equiv a (mod\ p) ap≡a(mod p),当 p p p为质数且 ( a , p ) = 1 (a,p)=1 (a,p)=1。
这样 a p − 2 = a − 1 a^{p-2}=a^{-1} ap−2=a−1,用快速幂求就好。
ll Reverse(ll op){
ll poi = mod - 2, base = op, res = 1;
while(poi){
if(poi&1)
res = (res*base) % mod; //在mod>INT_MAX时不适用。
base = (base*base) % mod;
poi >>= 1;
}
return res;
}
2-扩展欧几里得算法
a x + b y = ( a , b ) ax+by=(a,b) ax+by=(a,b)一定有解。
又设 b x ′ + ( a % b ) y ′ = ( a % b , b ) = ( a , b ) bx'+(a\%b)y'=(a\%b,b)=(a,b) bx′+(a%b)y′=(a%b,b)=(a,b),
则 a x + b y = b x ‘ + ( a % b ) y ’ = b x ′ + ( a − b ∗ ⌊ a / b ⌋ ) y ’ ax+by=bx‘+(a\%b)y’=bx'+(a-b*\lfloor a/b \rfloor)y’ ax+by=bx‘+(a%b)y’=bx′+(a−b∗⌊a/b⌋)y’
a x + b y = a y ′ + b ( x ′ − ⌊ a / b ⌋ y ′ ) ax+by=ay'+b(x'-\lfloor a/b \rfloor y') ax+by=ay′+b(x′−⌊a/b⌋y′)
因此 x = y ′ x=y' x=y′, y = x ′ − ⌊ a / b ⌋ y ′ y=x'-\lfloor a/b \rfloor y' y=x′−⌊a/b⌋y′。
只要求解 b x ′ + ( a % b ) y ′ = ( a , b ) bx'+(a\%b)y'=(a,b) bx′+(a%b)y′=(a,b),将 x ′ , y ′ x',y' x′,y′带入即可求出 x , y x,y x,y。
这样,我们可以像欧几里得算法一样不断减小系数的规模。只要递归地求解更小规模的方程,最后回溯时将解依次带回就好。递归终点是当 b i = 0 b_i=0 bi=0时,这时 ( a i , b i ) = a i = ( a , b ) (a_i,b_i)=a_i=(a,b) (ai,bi)=ai=(a,b), a i x i + b i y i = ( a i , b i ) a_ix_i+b_iy_i=(a_i,b_i) aixi+biyi=(ai,bi)一组解是 x i = 1 , y i = 0 x_i=1,y_i=0 xi=1,yi=0。
当 ( a , b ) = 1 (a,b)=1 (a,b)=1时, a x + b y = 1 ax+by=1 ax+by=1可用来求解 b b b在模 a a a意义下的逆元 y y y,或者 a a a在模 b b b意义下的逆元 x x x.
void exEuclid(ll a, ll b, ll &d, ll &x, ll &y){
if(!b)
d=a, x=1, y=0; //d就是gcd
else{
exEuclid(b, a % b, d, y, x);
y -= x * (a / b); //x=y', y=x' - y'*(a/b)
}
}
复杂度与辗转相除法相同 O ( l o g a b ) O(log\ ab) O(log ab),因为每一次都使较大的数减小一半以上。
3-线性递推法
需要 m o d mod mod是质数。
设 m o d = k ∗ i + r ≡ 0 mod = k*i+r\equiv 0 mod=k∗i+r≡0,
两边同乘 i − 1 r − 1 i^{-1}r^{-1} i−1r−1得
k ∗ r − 1 + i − 1 ≡ 0 k*r^{-1}+i^{-1}\equiv 0 k∗r−1+i−1≡0即
i − 1 ≡ m o d − k r − 1 i^{-1}\equiv mod-kr^{-1} i−1≡mod−kr−1。
其中 k = ⌊ m o d / i ⌋ k=\lfloor mod/i \rfloor k=⌊mod/i⌋, r = m o d % i r = mod\%i r=mod%i。
rev[1]=1;
for(int i=2; i<mod; i++)
rev[i]=(mod - mod/i)*rev[mod%i]%mod;
例题:[SCOI2010]生成字符串
许多需要求组合数的题目中都需要求逆元。本题求解的思路与求卡特兰数的推导过程非常相似。