其他分享
首页 > 其他分享> > 线性同余方程(扩展欧几里得应用)

线性同余方程(扩展欧几里得应用)

作者:互联网

线性同余方程(扩展欧几里得算法的应用)

题目内容

给定$n$组数据$a_i, b_i, m_i$, 对于每组数据求出一个$x_i$,使其满足$a_i \times x_i \equiv b_i(mod \ m_i)$

如果无解则输出impossible

输入格式

第一行包含整数 $n$,接下来$n$行,每行包含一组数据$ a_i, b_i, m_i$

输出格式

输出共$n$行, 每行数据输出一个整数表示一个满足条件的 $x_i$,如果无解则输出 impossible

每组数据结果占一行,结果可能不唯一,输出任意一个满足条件的结果均可。

输出答案必须在$int$ 范围之内

数据范围

$1 \le n \le 10^5$

$1 \le a_i,b_i,m_i \le 2 \times 10^9$

输入样例

2
2 3 6
4 3 5

输出样例

impossible
-3

一、问题解决

  1. 把 $ax \equiv b \ \ (mod \ m)$表示$ax - b$为$m$的倍数, 等价为 $ax = my + b$ , 变形可得 $ax-my=b$ .

  2. 令$y' = -y$,上式变为$ax + my' = b$,即线性同余方程方程等价为$ax + my = b$,

  3. 判断是否有解(详见第二部分是否有解)

  4. 运用欧几里得算法求出一组解$x_0, y_0$, 使得$ax_0 + my_0 = gcd(a,m)$ ,但题目本身是求$ax + my = b$,所以两边同时乘以$\frac{b}{gcd(a,m)}$即可,即$x = x_0 \times \frac{b}{gcd(a,b)} % \ m$

二、是否有解

引入一个定理:裴蜀定理(贝祖定理)

设$a,b$不全为零的整数,则存在整数$x, y$使得$ax + by = gcd(a, b)$

关于定理的证明: https://oi-wiki.org/math/number-theory/bezouts/

所以由裴蜀定理可知:

  1. 当$gcd(a,m) \ | \ b$时,方程有解

    整除的解释:'|' 整除号,如a|b (a不为0),若存在整数k,使得b=ka,则称a整除b

  2. 反之,方程无解

三、扩展欧几里得算法

用于求解$ax+by=gcd(a,b)$的解

  1. 当$b = 0$时,$ax = a$,此时$x = 1, y = 0$

    注意: 当a不为0时,gcd(a, 0) = gcd(0, a) = a

  2. 当$b \neq 0$时,由于$gcd(a, b) = gcd(b, a\ % \ b)$

    代入$ax + by = gcd(a, b)$中可联立方程
    $$
    \begin{aligned}
    & ax + by = gcd(a,b) \qquad \qquad \qquad①\
    & bx' + (a \ % \ b)y' = gcd(b, a\ % \ b)\ \quad②
    \end{aligned}
    $$
    因为$a % b = a - \lfloor {a/b}\rfloor \times b$,代入整理可得

    $ay' + b(x' - \lfloor a/b \rfloor \times y') = gcd(b,\ a % \ b) = gcd(a, b)$

    所以:
    $$
    x = y',y = x' - \lfloor a/b \rfloor \times y' \quad ③
    $$

所以可以利用递归算法,求出下一层的$x' 与 y'$,递归至边界$b = 0$时,$x = 1, y = 0$

,然后再利用公式③回代即可求解

五、C++代码

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
int n, x, y;
int exgcd(int a, int b, int &x, int &y){//ax + by = gcd(a, b)
    if(b == 0){
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, x, y);
    int z = x;
    x = y;
    y = z - a / b * y;
    return d;
}

int main(){
    cin >> n;
    while(n --){
        int a, b, m;
        cin >> a >> b >> m;
        //ax + my = b,传入参数要匹配
        int d = exgcd(a, m, x, y);
        if(b % d) cout << "impossible\n";
        else{
            x = (LL)x * b / d % m;
            cout << x << endl;
        }
    }
    return 0;
}

标签:输出,gcd,int,欧几里得,times,线性,ax,my,同余
来源: https://www.cnblogs.com/PlayfulBlueMoon/p/16396717.html