• gcd模板(欧几里得与扩展欧几里得、拓展欧几里得求逆元)


    gcd(欧几里得算法辗转相除法):

    gcd ( a , b )= d ;

    即 d = gcd ( a , b ) = gcd ( b , a mod b );以此式进行递归即可。

    之前一直愚蠢地以为辗转相除法输进去时 a 要大于 b ,现在发现事实上如果 a 小于 b,那第一次就会先交换 a 与 b。

     1 #include<stdio.h>
     2 #define ll long long 
     3 
     4 ll gcd(ll a,ll b){
     5     return b==0?a:gcd(b,a%b);
     6 }
     7 
     8 int main(){
     9     ll a,b;
    10     while(scanf("%lld%lld",&a,&b)!=EOF){
    11         printf("%lld
    ",gcd(a,b));
    12     //    printf("%lld
    ",a>b?gcd(a,b):gcd(b,a));
    13     }
    14     return 0;
    15 }
    View Code

    在原基础上改成循环之后的GCD:

    1 ll gcd(ll a,ll b){
    2     for(;a>0&&b>0;a>b?a%=b:b%=a);
    3     return a+b;
    4 }

    这个代码是针对非负数范围的,但除此之外我还纠结了很久,在非负数的范围内(long long内)与普通递归的gcd对拍并没有发现问题,一直做题的时候也没有发现有什么问题,但是刷到一题UVA10325,经测试数据中没有给0或负数,但是用这个WA用递归版的AC,并不知道为什么。

    所以……还是库函数/递归保平安吧

     

    拓展欧几里得:

    当 gcd ( a , b )= d 时,求绝对值和最小的 x , y 使得 x * a + y * b = d ;

    d = gcd ( a , b ) = gcd ( b , a mod b );

    设:

    x1 * a + y1 * b = d ;        ①

    x2 * b + y2 * ( a mod b ) = d ;   ②

    因为 a mod b = a - ( a / b )* b;  ③(除法为整除)

    将③代入①整理得:

    y2 * a + ( x2 - ( a / b ) * y2 ) * b = d; ④

    由①和④整理得:

    x1 = y2 ;

    y1 = x2 - ( a / b ) * y2;

    将此结论代入递归函数既得。

     1 #include<stdio.h>
     2 #define ll long long
     3 
     4 void gcd(ll a,ll b,ll& d,ll& x,ll& y){
     5     if(!b){d=a;x=1;y=0;}
     6     else {gcd(b,a%b,d,y,x);y-=x*(a/b);}
     7 }
     8 
     9 int main(){
    10     ll a,b,d,x,y;
    11     while(scanf("%lld%lld",&a,&b)!=EOF){
    12         gcd(a,b,d,x,y);
    13         printf("%lld*%lld+%lld*%lld=%lld
    ",a,x,b,y,d);
    14     }
    15     return 0;
    16 }
    View Code

     

    拓展欧几里得求逆元:

    当 a 与 b 互素时有 gcd ( a , b ) = 1 ;

    即得: a * x + b * y = 1;

    a * x ≡ 1 ( mod b );

    由于 a 与 b 互素,同余式两边可以同除 a ,得:

    1 * x ≡ 1 / a (mod b);

    因此 x 是 a mod b 的逆元;

    递归方法计算:

     1 #include<stdio.h>
     2 #define ll long long
     3 
     4 ll gcd(ll a,ll b,ll &d,ll& x,ll& y){
     5     if(!b){
     6         d=a;
     7         x=1;
     8         y=0;
     9         return x;
    10     }
    11     else{
    12         gcd(b,a%b,d,y,x);
    13         y-=x*(a/b);
    14     }
    15     return x;
    16 }
    17 
    18 int main(){
    19     ll a,b,d,x,y;
    20     while(scanf("%lld%lld",&a,&b)!=EOF){
    21         x=gcd(a,b,d,x,y);
    22         printf("a:%lld->x:%lld
    ",a,x);
    23 //        printf("a:%lld->x:%lld
    b:%lld->y:%lld
    ",a,x,b,y);
    24     }
    25     return 0;
    26 }
    View Code

    循环方法计算:

     1 #include<stdio.h>
     2 
     3 int main(){
     4     int a,b;
     5     while(scanf("%d%d",&a,&b)!=EOF){
     6         int x=1,y=0,t;
     7 
     8         {
     9             if(a!=1&&b!=1){
    10                 int b0=b,q;
    11                 while(a>1){
    12                     q=a/b0;
    13                     t=b0;b0=a%b0;a=t;
    14                     t=y;y=x-q*y;x=t;
    15                 }
    16                 if(x<0)x+=b;
    17             }
    18         }
    19 
    20         printf("a:%d->x:%d
    ",a,x);
    21     }
    22     return 0;
    23 }
    View Code
     1 ll gcd(ll a,ll b){
     2     if(a!=1&&b!=1){
     3         int b0=b,q,t,x=1,y=0;
     4         while(a>1){
     5             q=a/b0;
     6             t=b0;b0=a%b0;a=t;
     7             t=y;y=x-q*y;x=t;
     8         }
     9         if(x<0)x+=b;
    10     }
    11     return x;
    12 }
  • 相关阅读:
    IE6兼容问题
    清除浮动的几种方法
    CSS的继承性和层叠性
    CSS基础选择器复习
    梦与醒,进与退
    CSS的入门概念
    HTML的入门概念
    弹性布局整理
    点击评论加入输入框(笔记)
    css命名(笔记)
  • 原文地址:https://www.cnblogs.com/cenariusxz/p/4323872.html
Copyright © 2020-2023  润新知