洛谷 普及+/提高 P1082 [NOIP2012 提高组] 同余方程
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;
}