思路:
高精度结合更相减损术
更相减损术的语言描述:
转化为代码思路为:
对于 a,b 的 GCD(a,b)有:
[1]. 若 a 为奇数,b 为偶数,GCD(a,b)=GCD(a,b/2)
表示 b 存在2这个因子而 a 不存在,则将 b 除以2,,不考虑因子2;
[2]. 若 a 为偶数,b 为奇数,GCD(a,b)=GCD(a/2,b)
表示 a 存在2这个因子而 b 不存在,则将 a 除以2,不考虑因子2;
[3]. 若 a 为偶数,b 为偶数,GCD(a,b)=2GCD(a/2,b/2)
表示 a,b 都存在2这个因子,则 GCD(a,b) 也存在因子2,则将当前答案乘以2,a,b 都除以2;
[4]. 若 a 为奇数,b 为奇数,GCD(a,b)=GCD(a−b,b)(a>b)
例如求40与30的最大公因数
1)=2*gcd(20,15);
2)=2*gcd(15,10);
3)=2*gcd(15,5);
4)=2*gcd(10,5);
5)=2*gcd(5,5);
40与30的最大公因数为10;
代码:
#include<stdio.h>
#include<string.h>
typedef long long int ll;
struct Bignum {
int num[10010],len;
void clear() {memset(num,0,sizeof num);len=0;}
void operator-=(const Bignum &others) {
for(int i=1;i<=this->len;++i) {
this->num[i]-=others.num[i];
while(this->num[i]<0) {
this->num[i]+=10,--this->num[i+1];
}
}
while(!this->num[this->len]) --this->len;//去掉高位连续的0
if(!this->len) ++this->len;//如果结果为0,保证位数为1
}//重载运算符
bool operator!=(const Bignum &others) {
if(this->len!=others.len) return true;
for(int i=1;i<=this->len;++i) if(this->num[i] != others.num[i]) return true;
return false;
}//重载运算符
bool operator<(const Bignum &others) {
if(this->len!=others.len) return this->len<others.len;
for(int i=len;i;--i) if(this->num[i]!=others.num[i]) return this->num[i]<others.num[i];
return false;
}//重载运算符
Bignum operator*(const Bignum &others) {
Bignum _ans;_ans.clear();
int llen=this->len+others.len+5;
for(int i=1;i<=this->len;++i) {
for(int j=1;j<=others.len;++j) {
_ans.num[i+j-1]+=this->num[i]*others.num[j];
}
}//按位相乘
for(int i=1;i<=llen;++i) {
_ans.num[i+1]+=_ans.num[i]/10;
_ans.num[i]%=10;
}//在依次判断每一位上的数字是否合法,根据进制进位
_ans.len=llen;
while(!_ans.num[_ans.len]) --_ans.len;//去掉高位连续的0
if(!_ans.len) _ans.len=1;//如果结果为0,保证位数为1
return _ans;
}//重载运算符
};
Bignum a,b,ans;
char MU[10010];
int cnt;
void dv(Bignum&);
void mul(Bignum&);
void init(Bignum&,int);
void print(Bignum&);
int main() {
scanf("%s",MU+1);init(a,strlen(MU+1));
scanf("%s",MU+1);init(b,strlen(MU+1));//倒序存入
ans.num[1]=1;ans.len=1;
while(a != b) {
bool flag=false;
if(!((int(a.num[1])) & 1)) {dv(a);flag=true;}//如果a为偶数
if(!((int(b.num[1])) & 1)) {dv(b);if(flag) mul(ans);flag=true;}//如果b为偶数
if(flag) continue;//a或b为偶数
if(a < b) {b-=a;}
else {a-=b;}//a与b都为奇数
}//更相减损术
ans=ans*a;
print(ans);
putchar('\n');
return 0;
}
void init(Bignum &k,int l) {
for(int i=l;i;--i) k.num[++k.len]=MU[i]-'0';
}//倒着存入大整数
void dv(Bignum &k) {
int lst=0;
for(int i=k.len;i;--i) {
int _temp=k.num[i]+(lst<<1)+(lst<<3);
int _ans=_temp/2;
if(_temp & 1) lst=1;else lst=0;
k.num[i]=_ans;
}
while(!k.num[k.len]) --k.len;
return;
}
void mul(Bignum &k) {
int lst=0;k.len+=2;
for(int i=1;i<=k.len;++i) {
k.num[i]*=2;
k.num[i]+=lst;
lst=k.num[i]/10;k.num[i]%=10;
}
while(!k.num[k.len]) --k.len;
if(!k.len) ++k.len;
return;
}
void print(Bignum &k) {
for(int i=k.len;i>0;--i) putchar(k.num[i]+'0');
}