同余方程
同余:
设m是正整数,若 a a a和 b b b是整数,且 m ∣ ( a − b ) m|(a-b) m∣(a−b)(意思是 a − b a-b a−b能被 m m m整除),则 a a a和 b b b模 m m m同余 , a ≡ b ( m o d m ) ,a \equiv b \pmod {m} ,a≡b(modm) ,也就是说 a a a除以 m m m的余数等于 b b b除以 m m m的余数
现在我们考虑一元线性同余方程
a
x
≡
b
(
m
o
d
m
)
a x \equiv b \pmod {m}
ax≡b(modm)
,
a
>
0
,
n
>
0
,a>0,n>0
,a>0,n>0
它表示
a
x
−
b
ax-b
ax−b是
m
m
m的倍数,设为
−
y
-y
−y倍,则有二元线性丢番图方程
a
x
+
m
y
=
b
ax+my=b
ax+my=b,即求解一元线性同余方程等价于求解二元线性丢番图方程
如何求二元线性丢番图方程呢?
先给出一个推论:当且仅当 g c d ( a , m ) ∣ b gcd(a,m)|b gcd(a,m)∣b的时候,方程对于未知量 x x x有 g c d ( a , m ) gcd(a,m) gcd(a,m)个模 m m m不同余的解,另外,如果 ( x 0 , y 0 ) (x_0,y_0) (x0,y0)是方程的一个特解,那么所有的通解可以表示为 x = x 0 + n ( b / g c d ( a , m ) ) , y = y 0 − n ( a / g c d ( a , m ) ) x=x_0+n(b/gcd(a,m)),y=y_0-n(a/gcd(a,m)) x=x0+n(b/gcd(a,m)),y=y0−n(a/gcd(a,m)),其中 n n n为任意正整数
证明:
令
a
=
g
c
d
(
a
,
m
)
a
′
,
m
=
g
c
d
(
a
,
m
)
m
′
a=gcd(a,m)a',m=gcd(a,m)m'
a=gcd(a,m)a′,m=gcd(a,m)m′,有
a
x
+
m
y
=
g
c
d
(
a
,
m
)
(
a
′
x
+
m
′
y
)
=
b
ax+my=gcd(a,m)(a'x+m'y)=b
ax+my=gcd(a,m)(a′x+m′y)=b,所以如果
a
a
a和
m
m
m都是整数,那
b
b
b也必须是
g
c
d
(
a
,
m
)
gcd(a,m)
gcd(a,m)的整数倍才有整数解
所以问题转化为怎么求出这个二元方程 a x + m y = b ax+my=b ax+my=b的一个特解 ( x 0 , y 0 ) (x_0,y_0) (x0,y0),既然 g c d ( a , m ) ∣ b gcd(a,m)|b gcd(a,m)∣b,不如先求出 a x ′ + m y ′ = g c d ( a , m ) ax'+my'=gcd(a,m) ax′+my′=gcd(a,m),最后左右两边都乘以 b / g c d ( a , m ) b/gcd(a,m) b/gcd(a,m),
a x + m y = g c d ( a , m ) ax+my=gcd(a,m) ax+my=gcd(a,m) 扩展欧几里得算法
- 当 m = 0 m=0 m=0时, x = 1 , y = 0 x=1,y=0 x=1,y=0时等式成立
- 当
m
>
0
m>0
m>0时,已知:
g
c
d
(
a
,
m
)
=
g
c
d
(
m
,
a
−
m
)
=
g
c
d
(
m
,
a
gcd(a,m)=gcd(m,a-m)=gcd(m,a
gcd(a,m)=gcd(m,a−m)=gcd(m,a%
m
)
,
a
m),a
m),a%
m
=
a
−
m
∗
a
/
m
m=a-m*a/m
m=a−m∗a/m
则有 m x + ( a mx+(a mx+(a% m ) y = g c d ( m , a m)y=gcd(m,a m)y=gcd(m,a% m ) = g c d ( a , m ) m)=gcd(a,m) m)=gcd(a,m)
m x + ( a − m ∗ a / m ) y = g c d ( m , a mx+(a-m*a/m)y=gcd(m,a mx+(a−m∗a/m)y=gcd(m,a% m ) = g c d ( a , m ) m)=gcd(a,m) m)=gcd(a,m)
a y + m x − ( a / m ) ∗ m y = g c d ( a , m ) ay+mx-(a/m)*my=gcd(a,m) ay+mx−(a/m)∗my=gcd(a,m)
a y + m ( x − a / m ∗ y ) = g c d ( a , m ) ay+m(x-a/m*y)=gcd(a,m) ay+m(x−a/m∗y)=gcd(a,m)
对比
m
x
+
a
mx+a
mx+a%
m
∗
y
=
g
c
d
(
a
,
m
)
m*y=gcd(a,m)
m∗y=gcd(a,m)
所以
x
=
y
,
x=y,
x=y,
y
=
(
x
−
a
/
m
∗
y
)
,
y=(x-a/m*y),
y=(x−a/m∗y),
a
=
m
,
a=m,
a=m,
m
=
a
m=a
m=a%
m
m
m
typedef long long ll;
ll extend_gcd(ll a,ll m,ll &x,ll &y){//返回特解x0,y0
if(m==0){
x=1;y=0;
return a;
}else{
ll d=extend_gcd(m,a%m,y,x);//swap(x,y)
y-=(a/m)*x;//x,y交换了,这句容易出错
return d;//返回gcd(a,m)
}
}
得到了
a
x
′
+
m
y
′
=
g
c
d
(
a
,
m
)
ax'+my'=gcd(a,m)
ax′+my′=gcd(a,m)的特解
(
x
0
′
,
y
0
′
)
(x_0',y_0')
(x0′,y0′)
则
a
x
+
m
y
=
b
ax+my=b
ax+my=b的特解为
x
0
=
x
0
′
∗
b
/
g
c
d
(
a
,
m
)
,
y
0
=
y
0
′
∗
b
/
g
c
d
(
a
,
m
)
x_0=x_0'*b/gcd(a,m),y_0=y_0'*b/gcd(a,m)
x0=x0′∗b/gcd(a,m),y0=y0′∗b/gcd(a,m)
通解为
x
=
x
0
+
n
∗
(
b
/
g
c
d
(
a
,
m
)
)
,
y
=
y
0
−
n
∗
(
a
/
g
c
d
(
a
,
m
)
)
x=x_0+n*(b/gcd(a,m)),y=y_0-n*(a/gcd(a,m))
x=x0+n∗(b/gcd(a,m)),y=y0−n∗(a/gcd(a,m))
x=x0 + n*(b/__gcd(a,m));
y=y0 - n*(b/__gcd(a,m));
对于同余方程
a
x
≡
b
(
m
o
d
m
)
a x \equiv b \pmod {m}
ax≡b(modm)
,
a
>
0
,
n
>
0
,a>0,n>0
,a>0,n>0
调用
e
x
t
e
n
d
extend
extend_
g
c
d
(
a
,
m
,
x
,
y
)
gcd(a,m,x,y)
gcd(a,m,x,y),得出的
x
0
x_0
x0就是一个解,通解
x
=
x
0
+
(
m
/
g
c
d
(
a
,
m
)
)
∗
n
x=x_0+(m/gcd(a,m))*n
x=x0+(m/gcd(a,m))∗n,
0
≤
n
≤
d
−
1
0\le n\le d-1
0≤n≤d−1.,当
n
从
0
到
d
−
1
n从0到d-1
n从0到d−1,就取遍了模d的完全剩余系
x=x0+(m/__gcd(a,m))*n;
P1082
题目描述
求关于 x x x 的同余方程 a x ≡ 1 ( m o d b ) a x \equiv 1 \pmod {b} ax≡1(modb) 的最小正整数解。
输入格式
一行,包含两个整数 a , b a,b a,b,用一个空格隔开。
输出格式
一个整数 x 0 x_0 x0,即最小正整数解。输入数据保证一定有解。
样例 #1
样例输入 #1
3 10
样例输出 #1
7
数据规模与约定
- 对于 100 % 100\% 100% 的数据, 2 ≤ a , b ≤ 2 , 000 , 000 , 000 2 ≤a, b≤ 2,000,000,000 2≤a,b≤2,000,000,000。
a x ≡ 1 ( m o d b ) a x \equiv 1 \pmod {b} ax≡1(modb)即方程 a x + m y = 1 ax+my=1 ax+my=1,先用 e x t e n d extend extend_ g c d ( ) gcd() gcd()求出一个特解,然后用取模运算来得出最小正整数解
x=(x%m+m)%m;//保证返回正整数解
补充
a
x
≡
1
(
m
o
d
b
)
a x \equiv 1 \pmod {b}
ax≡1(modb)的解,为
a
a
a模
m
m
m的逆,记为
a
−
1
a^{-1}
a−1,所以扩展欧几里得算法就可以用来求逆,下面再介绍一种求逆的方法
费马小定理:设n是素数,a是正整数且与n互素,有
a
n
−
1
≡
1
(
m
o
d
n
)
a^{n-1}\equiv 1 \pmod {n}
an−1≡1(modn)
a
∗
a
n
−
2
≡
1
(
m
o
d
n
)
a*a^{n-2}\equiv1\pmod {n}
a∗an−2≡1(modn),那按照
a
n
−
2
(
m
o
d
n
)
a^{n-2}\pmod {n}
an−2(modn)就是
a
a
a模
n
n
n的逆!!!这个部分计算用快速幂取模来操作
但是!!!仅用费马小定理来测试素数是很危险的,原因是存在少量的伪素数也满足费马小定理,被称为Carmichael数,一亿个数里面大约有200多个,
欧几里得算法(辗转相除法)
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
Thanks♪(・ω・)ノ