ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-06-21 14:32:42  阅读:145  来源: 互联网

标签:输出 gcd int 欧几里得 times 线性 ax my 同余


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

题目内容

给定$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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有