初等数论基础(二)
建议先看
零、同余与逆元的概念
本来想直接记逆元的,但是发现初等数论基础一没有讲同余,于是先给出同余的概念:
0.1 同余
同余:若整数a和整数b除以m的余数相等,则称a,b模m同余,记为
a ≡ b ( m o d m ) a \equiv b(mod \quad m) a≡b(modm)
对于同余的概念需要掌握,另外有关于同余类和剩余系的概念,了解即可:
其实同余类和离散数学的等价类类似。
另外:同余具有传递性,也可以做加减:
0.2 逆元概念
对于正整数a和m,如果有am与1在模m意义下同余,那么这个同余方程中x的最小正整数解叫做a%m的逆元
注:逆元与乘法逆元不一样,除乘法逆元外还有加法逆元、卷积逆元、矩阵逆元等。
若
a x ≡ 1 ( m o d b ) , 则 称 x 是 a 关 于 模 b 的 逆 元 ax\equiv 1(mod\quad b),则称x是a关于模b的逆元 ax≡1(modb),则称x是a关于模b的逆元
一 般 把 一 个 数 a 的 逆 元 记 为 a − 1 一般把一个数a的逆元记为a^{-1} 一般把一个数a的逆元记为a−1
0.2.1 逆元的求法
1.exgcd求逆元
2.如果m是质数,可以通过快速幂求逆元(费马小定理)
3.如果模数是素数,可以O(n) 线性递推求逆元
方法1和方法2将在后面的内容中讲到,读者往后看即可,这里先给出第三种方法,线性递推求逆元
首先定义1的逆元是1,因为1显然与1同余
于是有代码:
typedef long long ll;
inv[i] = (1ll*(p-p/i)*inv[p%i])%p;
一、数论只会gcd
1.1 gcd
1.1.1 (a,b) = (a,a+b) 的证明
(a,a) = (a,0) = a(显然)
(a,b) = (a,a+b) = (a,ka+b)
(a,b) = (b,a%b)
1.1.2 (a,b) = (b,a%b)的证明
也叫辗转相除法
注意:gcd(a,b) = 1说明a和b互质。
另外:gcd(1,1) = 1,gcd(a,0) = a,gcd(a,1) = 1
辗转相除法代码:
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
//或者写成
ll gcd(ll a,ll b)
{
if(b==0)
{
return a;
}
return gcd(b,a%b);
}
辗转相除法时间复杂度
只知道是小于log2(b)的呜呜呜
小于log2(b) 很好证:
只需要证a%b<b/2就可以了
1.2 当然还会exgcd
啥?除了gcd还有exgcd????
在欧几里得求得gcd(a,b)以后,大家并不满足,于是好奇一个方程的解:
a
x
+
b
y
=
g
c
d
(
a
,
b
)
已
知
a
,
b
,
求
一
组
x
,
y
使
得
方
程
成
立
ax+by = gcd(a,b) \\已知a,b,求一组x,y使得方程成立
ax+by=gcd(a,b)已知a,b,求一组x,y使得方程成立
在将这个方程的解之前需要介绍裴蜀定理:
1.2.1 裴蜀定理
∀
a
,
b
,
∃
x
,
y
s
.
t
.
a
x
+
b
y
=
g
c
d
(
a
,
b
)
\forall a,b ,\exists x,y \quad s.t. \quad ax+by = gcd(a,b)
∀a,b,∃x,ys.t.ax+by=gcd(a,b)
哈,其实就是说1.2的方程一定是有解的
1.2.2 ax+by = gcd(a,b)的求解
先构造:
显然当b = 0时,有x = 1,y = 任意值(一般写成0)
对于b!=0的情况:
只要每次先把(2)式求出,那么(1)式的解也能出来了:)
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x = 1,y = 0;
return a;
}
int d = exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int main()
{
int n;
cin>>n;
while(n--)
{
int a,b,x,y;
cin>>a>>b;
exgcd(a,b,x,y);
cout<<x<<' '<<y<<endl;
}
return 0;
}
这里给出例题:)例题链接
分析:题目要求ax+by=c的解:
令d = gcd(a,b),显然只有c%d==0即d|c时该方程有解。
我们通过exgcd先求出ax+by=d的一组特解x0,y0,然后该方程的一组特解x1,y1通过x0,y0分别乘上c/d即可得到
而通解如何求解呢?
显然可以通过先求得的特解推通解,k是任意整数,显然加号和减号的位置可以互相交换。
二、欧拉相关
2.1 欧拉函数
详细定义见:初等数论基础一
2.2 欧拉定理相关
2.2.1 欧拉定理与费马小定理
2.2.1.1 欧拉定理
记为:
说人话就是:对于任意a与n互质,即有a的φ(n)次方与1在模n意义下同余。
例:
φ
(
7
)
=
6
,
3
φ
(
7
)
=
3
6
%
7
≡
1
(
m
o
d
7
)
\varphi(7) = 6,\quad 3^{\varphi(7)} = 3^6\%7 \equiv1(\mod 7)
φ(7)=6,3φ(7)=36%7≡1(mod7)
2.2.1.2 费马小定理
2.2.1.3 乘法逆元
例题:例题链接
容易发现,费马小定理就是欧拉定理的特殊情况。
2.2.2 扩展欧拉定理
引申:
若
b
>
φ
(
n
)
,
则
a
b
≡
a
b
%
φ
(
n
)
+
φ
(
n
)
(
m
o
d
n
)
若b>\varphi(n),则a^b \equiv a^{b\%\varphi(n)+\varphi(n)}( mod \quad n)
若b>φ(n),则ab≡ab%φ(n)+φ(n)(modn)
例题:
最幸运的数字
2.2.3 光速幂
例题:P5110
三、同余方程相关与逆元求解
3.1 线性同余方程
例题:线性同余方程
所以,当线性同余方程有解时只需要先用exgcd求解
a
x
+
m
y
=
g
c
d
(
a
,
m
)
,
得
到
一
组
特
解
x
0
,
y
0
然
后
x
=
x
0
∗
b
/
g
c
d
(
a
,
m
)
即
是
原
线
性
同
余
方
程
的
一
个
解
。
ax+my = gcd(a,m),得到一组特解x0,y0\\ 然后x = x0*b/gcd(a,m)即是原线性同余方程的一个解。
ax+my=gcd(a,m),得到一组特解x0,y0然后x=x0∗b/gcd(a,m)即是原线性同余方程的一个解。
容易发现:
线性同余方程
a
x
≡
b
(
m
o
d
m
)
即
转
化
为
a
x
+
m
y
=
b
,
然
后
通
过
e
x
g
c
d
求
解
ax\equiv b(mod\quad m)\\即转化为ax+my=b,然后通过exgcd求解
ax≡b(modm)即转化为ax+my=b,然后通过exgcd求解
例题链接
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a,b,x,y;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b)
{
x = 1,y = 0;
return a;
}
ll d = exgcd(b,a%b,y,x);
y -= a/b*x;
return d;
}
int main()
{
ll a,b,x,y;
cin>>a>>b;
exgcd(a,b,x,y);
cout<<(x%b+b)%b;
}
3.1.2 威尔逊定理
(p-1)的阶乘在模p意义下与-1同余。
(
p
−
1
)
!
≡
−
1
(
m
o
d
p
)
(p-1)!\equiv -1(mod\quad p)
(p−1)!≡−1(modp)
3.2 逆元求解
3.2.1 exgcd求逆元
我们知道:若
a
x
≡
1
(
m
o
d
b
)
ax\equiv 1(mod\quad b)
ax≡1(modb),则由线性同余方程可以转化为
a
x
+
b
y
=
1
ax+by=1
ax+by=1
那么可以直接调用扩展欧几里得算法求逆元。
3.2.2 快速幂求逆元
如果b为质数,则
φ
(
b
)
=
b
−
1
再
由
欧
拉
定
理
:
∴
a
b
−
1
≡
1
(
m
o
d
b
)
∵
a
∗
a
b
−
2
=
a
b
−
1
∴
a
在
模
b
意
义
下
的
逆
元
就
是
a
b
−
2
\varphi(b)=b-1\\再由欧拉定理:\\ \therefore a^{b-1} \equiv 1(mod\quad b)\\ \because a*a^{b-2} = a^{b-1}\\ \therefore a在模b意义下的逆元就是a^{b-2}
φ(b)=b−1再由欧拉定理:∴ab−1≡1(modb)∵a∗ab−2=ab−1∴a在模b意义下的逆元就是ab−2
于是可以快速幂求啦!
3.3 中国剩余定理(CRT)
中国剩余定理是干嘛的呢?
例如解以下方程组:
参考
《算法竞赛进阶指南》
大佬博客
这位大佬的博客激励我继续前进
关于同余的传递性和加减法的证明