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

洛谷 普及+/提高 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) 1a+0b=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 bx+(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(abab)=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+aybbay=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(xbay)=d
综上即回溯到上一层的推导过程。
因此: x = y ′ x=y' x=y y = x ′ − ⌊ a b ⌋ y ′ y=x'-\left\lfloor\dfrac{a}{b}\right\rfloor y' y=xbay
那么最终就构造出一组 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=y0ka
那么最小的正整数 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值