洛谷 P1082 同余方程

题目:
https://www.luogu.org/problemnew/show/P1082
代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
void exgcd(LL &x,LL &y,int a,int b)//扩展欧几里得算法
{
    if(b == 0){
        x = 1;
        y = 0;
        return;
    }
    exgcd(x,y,b,a % b);
    int temp = x;
    x = y;
    y = temp - a / b * y;
    return;
}
int main()
{
    int a,b;
    LL x,y;
    cin >> a >> b;
    exgcd(x,y,a,b);
    while(x < 0) x += b;//得到最小的正整数x
    x %= b;
    cout << x << endl;
    return 0;
}

题意:
已知a,b的值且ax≡1(modb),求x最小的正整数的解。

思路:
今天刚刚学了扩展欧几里得算法,就来做这道模板题了。
先来介绍一下什么是扩展欧几里得算法:
现在有方程:ax + by = c,现在要让你求方程的解x和y。
如果方程是有解的c % gcd(a,b)一定是为0的。(这里就不证明了)
假设现在有方程ax1 + by1 = gcd(a,b)
又因为gcd(a,b) = gcd(b,a % b)
且bx2 + (a % b) * y2 = gcd(b,a % b)
上面三式联立可得:bx2 + (a % b) * y2 = ax1 + by1
又因为a % b = a - (a / b) * b,然后代入上式得:
bx2 + [a - (a / b) * b] * y2 = ax1 + by1;
化简得:ay2 + (x2 - (a / b) * y2) * b = ax1 + by1
可以得出x1 = y2 y1 = x2 - (a / b) * y2
现在来考虑一下特殊情况,当b == 0时带入原式 ax + by = gcd(a,b)
得:ax = a ==》 x = 1,y = 0
到目前位置扩展欧几里得的算法就已经证完了,现在我们考虑该如何实现这一算法呢?
我们要知道x1,y1,那么就一定要知道y2,x2。就这样一步步推导,那我们可以知道,当b = 0的时候会产生一组特解,这也就是终止条件了。整个过程我们用递归实现,这个和普通的gcd实现过程十分相似,只不过添加了一些对于x,y的转换。

好了,那么再回到这道题上。知道a,b且知道ax ≡ 1(modb)。我们知道ax ≡ 1(modb)(这叫做ax和1在b下同余,不清楚可以百度同余)可以推出ax + by = 1,现在让你求x的最小正解。如果该方程有解那么gcd(a,b) = 1,也就是说a,b互质。现在用扩展欧几里得定理可以求出x的其中一组可行解,但是这个解不是最小的正整数解,为了能得到最小的正整数解,我们可以对x % b,如果x < 0,我们还需要每次把x都加上b直到x大于0,然后再%b。为何要这样做呢?下面我来稍微证明一下把!

因为ax + by = 1 ==》 y = (ax - 1) / b,因为得出的解x,y都是正数所以b是ax - 1的因子,也就是说ax - 1是b的倍数。如果现在x变化了b。可以推导出ax - 1依旧是b的倍数,这是y可以产生一个新的解。
那么如果x没有变化b呢?因为a,b互质,ax - 1就不是b的倍数了,这时候y就不会是一个整数了。所以算出一个x的值,如果x < 0,我们需要每次累加b,直到x > 0。如果x >= 0那么先不管它,最后都需要 % b。

刚开始学扩展欧几里得算法,证明也是看网上的,看了很久。如果写错的地方欢迎大家在下方留言。。。。

猜你喜欢

转载自blog.csdn.net/qq_41998938/article/details/89001986
今日推荐