当前位置: 代码迷 >> 综合 >> 洛谷 普及+/提高 P1082 [NOIP2012 提高组] 同余方程
  详细解决方案

洛谷 普及+/提高 P1082 [NOIP2012 提高组] 同余方程

热度:50   发布时间:2023-11-27 14:58:22.0

洛谷 普及+/提高 P1082 [NOIP2012 提高组] 同余方程

P1082 [NOIP2012 提高组] 同余方程

思路: a x ≡ 1 ( m o d b ) ax ≡ 1 \pmod b ax1(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 1xb+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 2xb+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 3xb+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;
}