乘法逆元
例题1
小凯的数字
一串数字l(l+1)(l+2)…(r-1)r,例如l=2,r=5,数字为2345,小凯很喜欢数字9,所以写下的数字除以9的余数是多少
2345 = 2 × 1 0 3 + 3 × 1 0 2 + 4 × 1 0 1 + 5 × 1 0 0 ∀ x ≧ 0 , 1 0 x m o d 9 = 1 ( 2 × 1 0 3 ) % 9 = ( 2 % 9 × 1 0 3 % 9 ) % 9 = 2 % 9 = 2 2345 % 9 = ( 2 × 1 0 3 + 3 × 1 0 2 + 4 × 1 0 1 + 5 × 1 0 0 ) % 9 = ( 2 + 3 + 4 + 5 ) % 9 = 5 ∴ a n s w e r = [ l + ( l + 1 ) + . . . + ( r − 1 ) + r ] % 9 = ( l + r ) ( r − l + 1 ) 2 % 9 2345=2\times 10^3+3\times 10^2+4\times 10^1+5\times 10^0\\ \forall x \geqq 0,10^x\mod 9=1\\ (2\times 10^3)\%9=(2\%9\times 10^3\%9)\%9=2\%9=2\\ 2345\%9=(2\times 10^3+3\times 10^2+4\times 10^1+5\times 10^0)\%9=(2+3+4+5)\%9=5\\ \therefore answer=[l+(l+1)+...+(r-1)+r]\%9=\frac{(l+r)(r-l+1)}{2}\%9 2345=2×103+3×102+4×101+5×100∀x≧0,10xmod9=1(2×103)%9=(2%9×103%9)%9=2%9=22345%9=(2×103+3×102+4×101+5×100)%9=(2+3+4+5)%9=5∴answer=[l+(l+1)+...+(r−1)+r]%9=2(l+r)(r−l+1)%9
因为模运算必须是整数,上面的 ( l + r ) ( r − l + 1 ) (l+r)(r-l+1) (l+r)(r−l+1)可以用整数计算,除以2就不一定还是整数了。
那么分数在模意义下该怎么表示呢?也就是说在mod p意义下,能不能表示 1 a \frac{1}{a} a1呢?
在实数意义下,对于任意的 a ≠ 0 a\neq 0 a=0,都有 a × 1 a = 1 a\times \frac{1}{a}=1 a×a1=1,所以在模意义下,也希望1/a也满足同样的性质: a × 1 a ≡ 1 ( m o d p ) a\times \frac{1}{a}\equiv 1(\mod p) a×a1≡1(modp),也就是说,尝试找到一个整数,满足 a × x ≡ 1 ( m o d p ) a\times x\equiv 1(\mod p) a×x≡1(modp)
定义
若 a × x ≡ 1 ( m o d p ) a\times x\equiv1(\mod p) a×x≡1(modp),则称x为a在模p意义下的乘法逆元,记为 a − 1 ( m o d p ) a^{-1}(\mod p) a−1(modp)
在本章种,模意义下的乘法逆元,简称为逆元。
2
×
5
m
o
d
9
=
10
m
o
d
9
=
1
∴
5
是
2
关于模
9
的逆元
也就是说,
1
2
在模
9
的意义下可以用
5
来表示
8
×
1
2
=
4
8
×
5
m
o
d
9
=
40
m
o
d
9
=
4
2\times 5\mod 9=10\mod 9=1\\ \therefore 5是2关于模9的逆元\\ 也就是说,\frac{1}{2}在模9的意义下可以用5来表示\\\\ 8\times \frac{1}{2}=4\\ 8\times 5\mod 9=40\mod 9=4\\
2×5mod9=10mod9=1∴5是2关于模9的逆元也就是说,21在模9的意义下可以用5来表示8×21=48×5mod9=40mod9=4
所以这题只需要求出
5
(
l
+
r
)
(
r
−
l
+
1
)
m
o
d
9
5(l+r)(r-l+1)\mod9
5(l+r)(r−l+1)mod9 为了降低处理的数量级,可以
5
(
l
+
r
)
%
9
(
r
−
l
+
1
)
%
9
m
o
d
9
5(l+r)\%9(r-l+1)\%9\mod9
5(l+r)%9(r−l+1)%9mod9
#include <bits/stdc++.h>
using namespace std;
int t;
long long l,r,ans;
int main()
{
cin>>t;
while(t--){
cin>>l>>r;
ans=((l+r)%9*(r-l+1)%9*5)%9;
cout<<ans<<endl;
}
return 0;
}
接下来,就从两种不同的方法给定一组a,p,求出a在模p意义下的逆元
方法1
拓展欧几里得算法
从 a × x ≡ 1 ( m o d p ) a\times x\equiv1(\mod p) a×x≡1(modp)入手,等价于 ∃ y , a x + p y = 1 \exists y,ax+py=1 ∃y,ax+py=1等价。实际上就是一个关于a,p的不定方程,就可以用拓展欧几里得算法来解决
并且由裴蜀定理,可以发现存在a在模p意义下的逆元当且仅当gcd(a,p)=1,a和p互质,即 a ⊥ p a\perp p a⊥p
int inv(int a,int p){ //用exgcd求逆元
int x,y;
exgcd(a,p,x,y);
//求不定方程ax+py=1的一组解
return x;
//求出的x就是a在模p的意义下的乘法逆元
}
方法2
费马小定理
若p为质数,且a不是p的倍数,则 a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv1(\mod p) ap−1≡1(modp)
假设p为质数,那么如果a不是p的倍数,就有 a × a p − 2 = a p − 1 ≡ 1 ( m o d p ) a\times a^{p-2}=a^{p-1}\equiv 1(\mod p) a×ap−2=ap−1≡1(modp)
所以a在模p意义下的逆元就是 a p − 2 a^{p-2} ap−2,可以用快速幂来解决。
如果a是p的倍数的话,对于任意x,ax也一定是p的倍数,不可能在模p的意义下等于1,也就不存在逆元了
int inv(int a,int p){ //用费马小定理求逆元
return pow(a,p-2,p);
//求出a^(p-2)mod p的值
}
不管什么方法,都可以求出一个a在模p的意义下的逆元
定理
在大于等于0,小于p的范围内,模p的逆元(若存在)是唯一的
假设
∃
0
≤
x
1
<
x
2
<
p
,
a
x
1
≡
a
x
2
≡
1
(
m
o
d
p
)
那么
a
(
x
2
−
x
1
)
≡
0
(
m
o
d
p
)
∴
a
(
x
2
−
x
1
)
是
p
的倍数
又
∵
a
⊥
p
∴
x
2
−
x
1
是
p
的倍数
∵
0
<
x
2
−
x
1
<
p
∴
x
2
−
x
1
不是
p
的倍数,矛盾
假设\exists 0\leq x_1<x_2<p,ax_1\equiv ax_2\equiv 1(\mod p)\\ 那么a(x_2-x_1)\equiv 0(\mod p)\\ \therefore a(x_2-x_1)是p的倍数\\ 又\because a\perp p\\ \therefore x_2-x_1是p的倍数\\ \because 0<x_2-x_1<p\\ \therefore x_2-x_1不是p的倍数,矛盾
假设∃0≤x1<x2<p,ax1≡ax2≡1(modp)那么a(x2−x1)≡0(modp)∴a(x2−x1)是p的倍数又∵a⊥p∴x2−x1是p的倍数∵0<x2−x1<p∴x2−x1不是p的倍数,矛盾
例题2
乘法逆元(线性时间)
给定n,q,求1~n中所有整数在模p意义下的乘法逆元
递推
假设已经知道了 1 到 i − 1 的逆元,现在要求 i 的逆元 初始情况 : 当 i = 1 时, i − 1 ≡ 1 ( m o d p ) 2 ≤ i < p 时 p = p / i × i + p % i 同余式 : p / i × i + p m o d i ≡ 0 ( m o d p ) ∵ p 为质数, 0 < p m o d i < i ∴ i 和 p m o d i 的逆元一定存在 在等式两边同时乘以 i − 1 ( p m o d i ) − 1 ( p m o d i ) − 1 × p / i + i − 1 ≡ 0 ( m o d p ) i − 1 ≡ − ( p m o d i ) − 1 × p / l ( m o d p ) 假设已经知道了1到i-1的逆元,现在要求i的逆元\\ 初始情况:当i=1时,i^{-1}\equiv 1(\mod p)\\ 2\leq i<p时\\ p=p/i\times i+p\%i\\ 同余式:p/i\times i+p\mod i\equiv0(\mod p)\\ \because p为质数,0<p\mod i<i\\ \therefore i和p\mod i的逆元一定存在\\ 在等式两边同时乘以i^{-1}(p\mod i)^{-1}\\ (p\mod i)^{-1}\times p/i+i^{-1}\equiv0(\mod p)\\ i^{-1}\equiv-(p\mod i)^{-1}\times p/l(\mod p) 假设已经知道了1到i−1的逆元,现在要求i的逆元初始情况:当i=1时,i−1≡1(modp)2≤i<p时p=p/i×i+p%i同余式:p/i×i+pmodi≡0(modp)∵p为质数,0<pmodi<i∴i和pmodi的逆元一定存在在等式两边同时乘以i−1(pmodi)−1(pmodi)−1×p/i+i−1≡0(modp)i−1≡−(pmodi)−1×p/l(modp)
#include <bits/stdc++.h>
using namespace std;
int n,p;
long long inv[3000010];
int main()
{
scanf("%d%d",&n,&p);
inv[1]=1;
//递推初始化
for(int i=2;i<=n;i++)
inv[i]=(p-inv[p%i]*(p/i)%p);
//i^(-1)=p-(p%i)^(-1)*(p/i)%p
for(int i=1;i<=n;i++)
printf("%lld\n",inv[i]);
return 0;
}
//卡cin、cout
倒推
直接倒推可能会比较困难,但是我们知道 1 k = ( k − 1 ) ! k ! \frac{1}{k}=\frac{(k-1)!}{k!} k1=k!(k−1)!,所以加入我们已经知道了1!,2!,…,n!mod p的结果,
并且已经知道了1!,2!,…,n!的逆元,就可以知道1到n的逆元了
1.
用循环求出
1
!
,
2
!
,
.
.
.
,
n
!
m
o
d
p
的结果
2.
用拓展那欧几里得算法
/
快速幂求出
n
!
的逆元
3.
根据
1
(
k
−
1
)
!
=
k
k
!
,
倒推出
(
n
−
1
)
!
,
(
n
−
2
)
!
,
.
.
.
,
1
!
的逆元
4.
根据
1
k
=
(
k
−
1
)
!
k
!
,求出
1
到
n
的逆元
1.用循环求出1!,2!,...,n!\mod p的结果\\ 2.用拓展那欧几里得算法/快速幂求出n!的逆元\\ 3.根据\frac{1}{(k-1)!}=\frac{k}{k!},倒推出(n-1)!,(n-2)!,...,1!的逆元\\ 4.根据\frac{1}{k}=\frac{(k-1)!}{k!},求出1到n的逆元\\
1.用循环求出1!,2!,...,n!modp的结果2.用拓展那欧几里得算法/快速幂求出n!的逆元3.根据(k−1)!1=k!k,倒推出(n−1)!,(n−2)!,...,1!的逆元4.根据k1=k!(k−1)!,求出1到n的逆元
时间复杂度为O(n+log n)
#include <bits/stdc++.h>
using namespace std;
int n,p;
long long inv[3000010],fac[3000010];
long long pow(long long x,int y,int p){
long long ans=1;
for(;y;y>>=1){
if(y&1) ans=ans*x%p;
x=x*x%p;
}
return ans;
}
int main()
{
scanf("%d%d",&n,&p);
fac[0]=1;
for(int i=1;i<=n;i++)
fac[i]=fac[i-1]*i%p;
//求出1!,2!,...,n!
inv[n]=pow(fac[n],p-2,p);
//求出(n!)^(-1)
for(int i=n-1;~i;i--){
inv[i]=inv[i+1]*(i+1)%p;
}
//求出((n-1)!^(-1),(n-2)!^(-1),...,1!^(-1))
for(int i=1;i<=n;i++)
printf("%lld\n",fac[i-1]*inv[i]%p);
//求出1^(-1),2^(-1),...,n^(-1)
return 0;
}