• 拓展欧几里得算法思路解释、代码以及例题【线性同余方程】


     引入裴蜀定理

    有任意一对正整数a、b,一定存在非零整数x、y,使得a*x+b*y=gcd(a,b),且gcd(a,b)是a、b添加系数后凑出来的最小正整数。

    证明一下:

    假设a*x+b*y=d

    则需要证明的是:d是gcd(a,b)的倍数

    因为a是gcd(a,b)的倍数,b是gcd(a,b)的倍数,

    则 a*x+b*y也是gcd(a,b)的倍数

    所以我们求的gcd(a,b)是a、b添加系数后凑出来的最小正整数。

    那我们想证明一定存在的话,就是我们要接下来要说的拓展欧几里得算法了。

    拓展欧几里得算法是为了算出这样的一组x,y

    题目链接:877. 扩展欧几里得算法 - AcWing题库

    题面:

     

    采用递归的思路来求解:

    当b==0时,任何数与0的最大公约数都是它本身。

    当b==0时,a*x+0*y=a要成立的话,一组解为x=1,y=0;

    其他的情况就是一直递归:

    int d=exgcd(b,a%b,y,x),这里可以注意到这里传入的数值顺序改变了,读者自行理解一下

    我们就有了这个式子:gcd(a,b)=gcd(b*y+a%b*x)

    而a%b=a-a/b*b    (a/b注意向下取整)

    展开右边有:d=b*y+a*x-a/b*x

                           =a*x+b(y-a/b*x)

                    即

                    y=y-a/b*x;

                    x=x;

    代码:

    1. #include<bits/stdc++.h>
    2. using namespace std;
    3. typedef long long ll;
    4. const int N=1e6+10;
    5. const int mod=1e9+7;
    6. int exgcd(int a,int b,int &x,int &y)
    7. {
    8. if(!b)
    9. {
    10. x=1,y=0;
    11. return a;
    12. }
    13. int d=exgcd(b,a%b,y,x);
    14. y=y-a/b*x;
    15. return d;
    16. }
    17. int main()
    18. {
    19. ios::sync_with_stdio(false);
    20. cin.tie(0);
    21. cout.tie(0);
    22. ll n;
    23. cin>>n;
    24. while(n--)
    25. {
    26. int a,b,x,y;
    27. cin>>a>>b;
    28. exgcd(a,b,x,y);
    29. cout<<x<<" " <<y<<endl;
    30. }
    31. return 0;
    32. }

    拓展欧几里得算法例题:

    题目链接:878. 线性同余方程 - AcWing题库

    题面:

     

    思路:

    题目要求的是满足 ai × xi bi (mod mi)的xi。

    举个例子a=4,b=3,m=5时,4 * x % 5 = 3 % 5, x = 2 或 -3 (2,-3互余于5)

    由此我们只需要找出a * x % m = b

    [所以存在一个正整数y ,使得上式等价变形为] a * x = y * m + b

     a * x - y * m = b

    有上面的拓展欧几里得算法解释,我们可以知道,b一定是gcd(a,b)的倍数,否者不存在x

    如果是倍数的话,x可以表示为x*( b / gcd(a,b) ) % m。

    代码:

    1. #include<bits/stdc++.h>
    2. using namespace std;
    3. typedef long long ll;
    4. const int N=1e6+10;
    5. const int mod=1e9+7;
    6. //拓展欧几里得算法模板
    7. int exgcd(int a,int b,int &x,int &y)
    8. {
    9. if(!b)
    10. {
    11. x=1,y=0;
    12. return a;
    13. }
    14. int d=exgcd(b,a%b,y,x);
    15. y=y-a/b*x;
    16. return d;
    17. }
    18. int main()
    19. {
    20. ios::sync_with_stdio(false);
    21. cin.tie(0);
    22. cout.tie(0);
    23. ll n;
    24. cin>>n;
    25. while(n--)
    26. {
    27. int a,b,m;
    28. cin>>a>>b>>m;
    29. int x,y;
    30. int d=exgcd(a,m,x,y);//求出来了a,b的最大公约数
    31. if(b%d!=0)//即b不是gcd(a,b)的倍数
    32. cout<<"impossible"<<endl;
    33. else cout<<(ll)x*(b/d)%m<<endl;
    34. }
    35. return 0;
    36. }

  • 相关阅读:
    基于分布式光纤应变感知的铁路重点线路(区段)隧道监测设计
    高教版《管理学》(第四版)重点知识整理
    Java 将HTML转为Word
    Linux 基础 + Web 部署
    SeaTunnel 学习笔记
    Tomcat+Filebeat+logstash+ES+Kibana日志监控配置(待续)
    C01——挤牛奶
    Linux(二)LED驱动程序框架(总线设备驱动)
    CodeForces Round #821 (div.2) A~C
    数据可视化之百变柱状图
  • 原文地址:https://blog.csdn.net/WSY444/article/details/125594804