高精度GCD----super GCD 洛谷P2152

11 篇文章 0 订阅

思路:

高精度结合更相减损术

更相减损术的语言描述:

转化为代码思路为:

对于 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');
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值