第四章 数学知识 扩展欧几里得算法

1、扩展欧几里得算法

已知整数a、b,扩展欧几里得算法可以在求得a、b的最大公约数的同时,能找到整数x、y(其中一个很可能是负数),使它们满足等式 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)
ps:这个gcd(a,b)是a和b能凑出来的最小的正整数


int exgcd(int a, int b, int &x, int &y)
{
   if(b == 0)
   {
       x = 1,y = 0;
       return a;
   }
   //注意这里调换了一下x,y,这样可以在下面只变化y,不用变x
   int d = exgcd(b,a % b,y,x);
   y -= a / b * x;
   return d;
}

当b == 0 的时候,gcd(a,b) == a,所以只需要令x == 1,y == 0即可。
当b != 0 的时候,我们继续递归得到d的时候,我们已经有了
by + (a % b)x = d,此时我们希望通过这个式子得到我们当前的ax+by的凑法,只需要将上式进行等价变形:
b y + ( a % b ) x = b y + ( a − a / b ∗ b ) x = a x + b ( y − a / b ∗ x ) by + (a \% b)x = by + (a - a / b * b)x = ax + b(y - a / b * x) by+(a%b)x=by+(aa/bb)x=ax+b(ya/bx)
由此得到x = x,y = (y - a / b * x)

2、线性同余方程

利用扩展欧几里得方法可以轻松解决线性同余方程。
有如下的线性同余方程
a x ≡ b ( m o d   m ) ax \equiv b(mod\ m) axb(mod m)
这等价于存在整数y使得 a x = m y + b ax = my + b ax=my+b,也即 a x − m y = b ax - my = b axmy=b
此方程有解当且仅当gcd(a,m) | b

因为a是gcd(a,m)的倍数,m也是gcd(a,m)的倍数,所以他们两个的线性组合也是gcd(a,m)的倍数。如果b不是,那么就没有解

1. 例题线性同余方程

给定 n 组数据 ai,bi,mi,对于每组数求出一个 xi,使其满足 ai×xi≡bi(modmi),如果无解则输出 impossible。

输入格式
第一行包含整数 n。

接下来 n 行,每行包含一组数据 ai,bi,mi。
输出格式
输出共 n 行,每组数据输出一个整数表示一个满足条件的 xi,如果无解则输出 impossible。

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

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

数据范围
1≤n≤105,
1≤ai,bi,mi≤2×109
输入样例:
2
2 3 6
4 3 5
输出样例:
impossible
-3
#include<iostream>
using namespace std;
int exgcd(int a, int b, int &x, int &y)
{
    if(b == 0)
    {
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y , x);
    y -= a / b * x;
    return d;
}
int main()
{
    int n;
    cin >> n;
    while(n --)
    {
      int a,b,m,x,y;
      cin >> a >> b >> m;
      int d = exgcd(a,m,x,y);
      if(b % d == 0)
      {
          x = b / d * (long long)x % m;
          cout << x << endl;
      }else{
          cout << "impossible" << endl;
      }
    }
}

只需要解释一下,最后将x扩大了 b/d 倍,再对m取模之后,才是最后的结果

3、使用扩展欧几里得方法求逆元

a有逆元的充要条件是a与p互质,所以gcd(a, p) = 1。假设a的逆元为x,那么有a * x ≡ 1 (mod p)
等价:ax + py = 1。如果d= exgcd(a, p, x, y) == 1那么二者之间存在乘法逆元,否则二者有公因子,不存在乘法逆元。

int d = exgcd(a, p, x, y);
if (d == 1) cout << ((LL)x + p) % p << endl;//保证x是正数
else puts("impossible");

参考资料

https://www.acwing.com/solution/content/3054/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值