【SDOI2009】Super Gcd

题目描述

Sheng bill有着惊人的心算能力,甚至能用大脑计算出两个巨大的数的GCD(最大公约 数)!因此他经常和别人比赛计算GCD。有一天Sheng bill很嚣张地找到了你,并要求和你比 赛,但是输给Sheng bill岂不是很丢脸!所以你决定写一个程序来教训他。

输入格式:

共两行: 第一行:一个数A第二行:一个数B。

输出格式:

一行,表示A和B的最大公约数。

说明

对于 20 % 20\% 20%的数据, 0 ≤ A , B ≤ 1 0 18 0\leq A,B≤10^{18} 0A,B1018
对于 100 % 100\% 100%的数据, 0 ≤ A , B ≤ 1 0 1000 0\leq A,B≤10^{1000} 0A,B101000

题解

更相减损法大致思路:
对于 a,b 的 GCD(a, b) 有:

  • 若 a 为奇数, b 为偶数, G C D ( a , b ) = G C D ( a , b 2 ) GCD(a, b) = GCD(a, \frac{b}{2}) GCD(a,b)=GCD(a,2b)
    表示 b 存在2这个因子而 a不存在,则将 b除以2,,不考虑因子2;
  • 若 a 为偶数, b 为奇数, G C D ( a , b ) = G C D ( a 2 , b ) GCD(a, b) = GCD(\frac{a}{2}, b) GCD(a,b)=GCD(2a,b)
    表示a存在2这个因子而b不存在,则将a除以2,不考虑因子2;
  • 若a为偶数,b为偶数, G C D ( a , b ) = G C D ( a 2 , b 2 ) GCD(a, b) = GCD\left( \frac{a}{2}, \frac{b}{2}\right) GCD(a,b)=GCD(2a,2b)
    表示 a,b 都存在2这个因子,则 G C D ( a , b ) GCD(a, b) GCD(a,b)也存在因子2,则将当前答案乘以2, a,b 都除以2;
  • 若 a 为奇数, b 为奇数, G C D ( a , b ) = G C D ( a − b , b ) ( a > b ) GCD(a, b) = GCD(a - b, b) (a > b) GCD(a,b)=GCD(ab,b)(a>b)

Code

#pragma GCC optimize(2)
#include<cstdio>
#include<cstring>
const int N = 1e4  +10;
char s[N];
struct BigNum
{
	int len,num[N];
	friend BigNum operator /(const BigNum&a,const int&b)
	{
		BigNum tmp=a;int num=0;
		for(int i=tmp.len;i;i--)
		{
			num=num*10+a.num[i];
			tmp.num[i]=num/b;
			num%=b;
		}
		while(tmp.num[tmp.len]==0&&tmp.len>1)tmp.len--;
		return tmp;
	}
	int cmp(const BigNum&b)const
	{
		if(len<b.len)return -1;
		if(len>b.len)return 1;
		for(int i=len;i;i--)
		{
			if(num[i]<b.num[i])return -1;
			if(num[i]>b.num[i])return 1;
		}
		return 0;
	}
	friend BigNum operator -(BigNum&a,const BigNum&b)
	{
		BigNum tmp;tmp.len=a.len;
		for(int i=1;i<=tmp.len;i++)
		{
			if(a.num[i]<b.num[i])a.num[i]+=10,a.num[i+1]--;
			tmp.num[i]=a.num[i]-b.num[i];
		}
		while(tmp.num[tmp.len]==0&&tmp.len>1)tmp.len--;
		return tmp;
	}
	friend BigNum operator *(const BigNum&a,const int&b)
	{
		BigNum tmp;tmp.len=a.len;memset(tmp.num,0,sizeof(tmp.num));
		for(int i=1;i<=tmp.len;i++)
		{
			tmp.num[i]+=a.num[i]*b;
			if(tmp.num[i]>9)
			{
				tmp.num[i+1]+=tmp.num[i]/10;tmp.num[i]%=10;if(tmp.len==i)tmp.len++;
			}
		}
		return tmp;
	}
}a,b;
int main()
{
    scanf("%s",s+1);
    a.len=strlen(s+1);
    for(int i=1;i<=a.len;i++)a.num[a.len-i+1]=s[i]-'0';
    scanf("%s",s+1);
    b.len=strlen(s+1);
    for(int i=1;i<=b.len;i++)b.num[b.len-i+1]=s[i]-'0';
    int dou=0;
    while(!(a.num[1]&1)&&!(b.num[1]&1))dou++,a=a/2,b=b/2;
    while(!(a.num[1]&1))a=a/2;while(!(b.num[1]&1))b=b/2;
    while(a.cmp(b)!=0)
    {
    	if(a.cmp(b)==1)a=a-b;else b=b-a;
    	while(!(a.num[1]&1))a=a/2;while(!(b.num[1]&1))b=b/2;
	}
	while(dou--)a=a*2;
	for(int i=a.len;i;i--)printf("%d",a.num[i]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值