zoukankan      html  css  js  c++  java
  • 数论之扩展欧几里德

    扩展欧几里德首先要提到的是裴蜀定理:

      设 gcd(a,b)=c,则对于任意实数 x,y 有 c|ax+by 成立

      特别的,一定存在 x,y 满足 ax+by=c

      推论:a,b 互质等价于 ax+by=1 有解。

      求解 x,y:

      设 a>b。

      (1) 当 a mod b =0 时,gcd(a,b)=b。此时 x=0,y=1。

        因为 0*a+1*b=b

      (2) 当 a mod b!=0 时

      设 ax1+by1=gcd(a,b),bx2+(a mod b)y2=gcd(b,a mod b);

      据欧几里德原理有:ax1+by1=bx2+(a mod b)y2;

      因为   a mod b=a-(a/b)*b;

      则有:ax1+by1=bx2+(a-a(a/b)*b)y2

      根据恒等原理有: x1=y2,y1=x2-(a/b)*y2;

      于是我们便有了代码:

     1 #include <cstdio>
     2 using namespace std;
     3 long long a,b,x,y;
     4 
     5 void exgcd(long long a,long long b,long long &x,long long &y)
     6 {
     7     if(a%b==0)
     8     {
     9         x=0;y=1;return ;
    10     }
    11     exgcd(b,a%b,x,y);
    12     long long t=x;
    13     x=y;y=t-(a/b)*y;
    14 }
    15 
    16 int main()
    17 {
    18     scanf("%lld%lld",&a,&b);
    19     exgcd(a,b,x,y);
    20     printf("%lld%lld",x,y);
    21     return 0;
    22 }
    View Code

      其实,这个代码还有个压缩版本:

     1 #include <cstdio>
     2 using namespace std;
     3 long long a,b,x,y;
     4 
     5 void exgcd(long long a,long long b,long long &x,long long &y)
     6 {
     7     if(a%b==0)
     8     {
     9         x=0;y=1;return ;
    10     }
    11     exgcd(b,a%b,y,x);        //注意了, y 在前, x 在后 
    12     y-=x*(a/b); 
    13 }
    14 
    15 int main()
    16 {
    17     scanf("%lld%lld",&a,&b);
    18     exgcd(a,b,x,y);
    19     printf("%lld%lld",x,y);
    20     return 0;
    21 }
    View Code

    扩展欧几里德可以用来解二元一次不定方程

      例如:不定方程ax+by=d

      设 c=gcd(a,b);

      先用扩欧解出 ax+by=c 的解 x0,y0

      x0=x0*d/c; y0=y0*d/c。

      x,y的通解为

                x=x0+b/c*t;

                y=y0+a/c*t;

      不定方程 ax+by=d 有整数解的条件:

                d mod gcd(a,b)==0

      求解 x 的最小非负整数解:

     1 #include <cstdio>
     2 using namespace std;
     3 long long a,b,c,d,x0,y0,x;
     4 
     5 long long gcd(long long x,long long y)
     6 {
     7     return (x%y==0)?y:gcd(y,x%y);
     8 }
     9 
    10 void exgcd(long long a,long long b,long long &x,long long &y)
    11 {
    12     if(a%b==0)
    13     {
    14         x=0;y=1;return ;
    15     }
    16     exgcd(b,a%b,y,x);
    17     y-=x*(a/b); 
    18 }
    19 
    20 int main()
    21 {
    22     scanf("%lld%lld%lld",&a,&b,&d);
    23     c=gcd(a,b);
    24     if(d%c)
    25     {
    26         puts("No solution.");return 0;
    27     }
    28     a/=c;b/=c;d/=c;
    29     exgcd(a,b,x0,y0);
    30     x=x0%b;
    31     while(x<0)x+=b;
    32     printf("%lld",x);
    33     return 0;
    34 }
    View Code

      例题:poj 1061 青蛙的约会

  • 相关阅读:
    markown 画图
    C++ 结构体指针
    C++指针详解
    C++ 中类对象与类指针的区别
    Java面向对象㈠ -- 封装
    path和classpath
    "System.Web" 中不存在类型或命名空间
    ASP.NET 后台不识别ASPX中的控件
    asp.net中的<%%>形式的详细用法实例讲解
    ASP.NET前台JS与后台CS函数如何互相调用
  • 原文地址:https://www.cnblogs.com/lzxzy-blog/p/10307759.html
Copyright © 2011-2022 走看看