辗转相除法
使用到的原理很聪明也很简单,假设用f(x, y)表示x,y的最大公约数,取k = x/y,b = x%y,则x = ky + b,如果一个数能够同时整除x和y,则必能同时整除b和y;而能够同时整除b和y的数也必能同时整除x和y,即x和y的公约数与b和y的公约数是相同的,其最大公约数也是相同的,则有f(x, y)= f(y, x % y)(y > 0),如此便可把原问题转化为求两个更小数的最大公约数,直到其中一个数为0,剩下的另外一个数就是两者最大的公约数。gcd递归定理是指gcd(a,b)=gcd(b,a%b)
//直接调用 #include <iostream> #include <algorithm> using namespace std; int a,b; int main() { cin>>a>>b; cout<<__gcd(a,b)<<endl; return 0; } // int gcd(int a,int b){ if (b == 0) return a; else return gcd(b,a % b); }
高精度gcd
(更相减损术)
不妨设a<=b,则有:
1.a=b时, gcd(a,b)=a;
2.a,b均为偶数时,gcd(a,b)=2*gcd(a/2,b/2);
3.a为偶,b为奇时,gcd(a,b)=gcd(a/2,b);
4.a为奇,b为偶时,gcd(a,b)=gcd(a,b/2);
5.a,b均为奇数时,gcd(a,b)=gcd(a-b,b);
//输入两个数(分两行)输出最大公约数 #include<bits/stdc++.h> #define str strlen #define ll long long using namespace std; struct huge{ int num[10010]; int len; }; huge a,b; char d[10010];char c[10010]; void print(huge x){ for(int i=x.len-1;i>=0;i--) cout<<x.num[i]; // cout<<endl; } int smp (huge x,huge y){ if(x.len>y.len) return 1; if(x.len<y.len) return 2; for(int i=x.len-1;i>=0;i--){ if(x.num[i]>y.num[i]) return 1; if(x.num[i]<y.num[i]) return 2; } return 3; } huge ch(huge x){ int plus=0; for(int i=0;i<=x.len-1;i++){ x.num[i]*=2; x.num[i]+=plus;plus=0; if(x.num[i]>=10){ plus=x.num[i]/10; x.num[i]%=10; } } if(plus!=0){ x.len++; x.num[x.len-1]=plus; } return x; } huge chu(huge x){ for(int i=x.len-1;i>=0;i--){ if(x.num[i]%2==1){ x.num[i]--; x.num[i-1]+=10; } x.num[i]/=2; } while(x.num[x.len-1]==0&&x.len>1) x.len--; return x; } huge minu(huge x,huge y){ for(int i=0;i<x.len;i++){ if(x.num[i]<y.num[i]){ x.num[i]+=10; x.num[i+1]--; } x.num[i]-=y.num[i]; } while(x.num[x.len-1]==0&&x.len>1) x.len--; return x; } void gcd(huge x,huge y){ int xx=smp(x,y),aa=1-x.num[0]%2,bb=1-y.num[0]%2; int tt=0; while(xx<3){//print(x);print(y); if(xx==2){ swap(x,y); swap(aa,bb); } if(aa==1&&bb==1){ x=chu(x);y=chu(y); tt++; } if(aa==1&&bb==0) x=chu(x); if(aa==0&&bb==1) y=chu(y); if(aa==0&&bb==0) x=minu(x,y); xx=smp(x,y);aa=1-x.num[0]%2;bb=1-y.num[0]%2; } for(int i=1;i<=tt;i++) x=ch(x); print(x); return; } int main(){ scanf("%s",&c); scanf("%s",&d); if(str(c)<str(d)||(str(c)==str(d)&&strcmp(d,c)>0)) swap(c,d); a.len=str(c);b.len=str(d); for(int i=0;i<a.len;i++) a.num[i]=(int)(c[a.len-i-1]-'0'); for(int i=0;i<b.len;i++) b.num[i]=(int)(d[b.len-i-1]-'0'); gcd(a,b); return 0; }
//循环 ll gcd(ll a,ll b) { ll t; while(b)///当b为0时,得出结果,a既为结果 { t=b;///存b b=(a%b);///b为a对b取模 a=t;///a为上一次的b } return a; }
贝祖定理:其内容是若设a,b是整数,则存在整数x,y,使得ax+by=gcd(a,b),(a,b)代表最大公因数,则设a,b是不全为零的整数,则存在整数x,y,使得ax+by=(a,b)。
| 介是什么符号:
若b可被a整除,或a整除b,则可记作a|b
如2|6,8|16
性质:①a|b,b|c => a|c
②a|b,a|c => a|(b+c)=>a|(mb+nc) (m,n∈Z)
③a|b(a≠0) =>|a|≤|b|