洛谷 普及+/提高 P1082 [NOIP2012 提高组] 同余方程
思路: a x ≡ 1 ( m o d b ) ax ≡ 1 \pmod b ax≡1(modb) ⇒ \Rightarrow ⇒ 必定存在 k k k使得 a x + b y = 1 ax + by =1 ax+by=1,因为 a a a和 b b b必定是 g c d ( a , b ) gcd(a,b) gcd(a,b)的倍数,所以 a x + b y ax+by ax+by也一定是 g c d ( a , b ) gcd(a,b) gcd(a,b)的倍数。则假设 g c d ( a , b ) = d gcd(a,b) = d gcd(a,b)=d 那么存在数据 x x x和 y y y使得 a x + b y = d ax+by=d ax+by=d那么我们可以通过扩展欧几里得原理回溯出一组数据(构造)使得 g c d ( a , b ) = d gcd(a,b) = d gcd(a,b)=d 核心代码如下:
核心代码:
void exgcd(int a,int b,int &x,int &y){
if(!b){
x=1,y=0;
return ;
}
exgcd(b,a%b,y,x);
y-=x*(a/b);
}
推导过程: 当 b = 0 b=0 b=0时构造 x = 1 , y = 0 x=1,y=0 x=1,y=0存在 1 ∗ a + 0 ∗ b = g c d ( a , b ) 1*a+0*b=gcd(a,b) 1∗a+0∗b=gcd(a,b)。假设已经求出后面两个的系数(在代码中则是 e x g c d ( b , a m o d b ) ) exgcd(b,a{~}mod{~}b)) exgcd(b,a mod b))先继续往下递归得到下一个状态 g c d ( b , a m o d b ) gcd(b,a{~}mod{~}b) gcd(b,a mod b)和一组 x ′ , y ′ x',y' x′,y′使得 b ∗ x ′ + ( a m o d b ) ∗ y ′ = g c d b * x'+(a{~}mod{~}b) * y'=gcd b∗x′+(a mod b)∗y′=gcd进行以下递推:
1
:
x
′
b
+
y
′
(
a
m
o
d
b
)
=
d
1:x'b+y'(a{~}mod{~}b)=d
1:x′b+y′(a mod b)=d
2
:
x
′
b
+
y
′
(
a
−
⌊
a
b
⌋
∗
b
)
=
d
2:x'b+y'(a-\left\lfloor\dfrac{a}{b}\right\rfloor * b)=d
2:x′b+y′(a−⌊ba⌋∗b)=d
3
:
x
′
b
+
a
y
′
−
b
⌊
a
b
⌋
y
′
=
d
3:x'b+ay'-b\left\lfloor\dfrac{a}{b}\right\rfloor y' = d
3:x′b+ay′−b⌊ba⌋y′=d
4
:
a
y
′
+
b
(
x
′
−
⌊
a
b
⌋
y
′
)
=
d
4:ay'+b(x'-\left\lfloor\dfrac{a}{b}\right\rfloor y')=d
4:ay′+b(x′−⌊ba⌋y′)=d
综上即回溯到上一层的推导过程。
因此:
x
=
y
′
x=y'
x=y′ 且
y
=
x
′
−
⌊
a
b
⌋
y
′
y=x'-\left\lfloor\dfrac{a}{b}\right\rfloor y'
y=x′−⌊ba⌋y′
那么最终就构造出一组
x
,
y
x,y
x,y使得
a
x
+
b
y
=
d
ax+by=d
ax+by=d。由于本题必定有解。那么如何使得
x
x
x是最小的正整数呢。易得
x
x
x的所有解为:
x
=
x
0
+
k
b
x=x0+kb
x=x0+kb
y
=
y
0
−
k
a
y=y0-ka
y=y0−ka
那么最小的正整数
x
x
x即
(
x
(x
(x%
b
+
b
)
b+b)
b+b)%
b
b
b 考虑负数情况。
- 参考代码:
#include<bits/stdc++.h>
using namespace std;
void exgcd(int a,int b,int &x,int &y){
if(!b){
x=1,y=0;
return ;
}
exgcd(b,a%b,y,x);
y-=x*(a/b);
}
int main(){
int a,b;
cin>>a>>b;
int x,y;
exgcd(a,b,x,y);
cout<<(x%b+b)%b<<endl;
return 0;
}