题目描述
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}
0≤A,B≤1018
对于
100
%
100\%
100%的数据,
0
≤
A
,
B
≤
1
0
1000
0\leq A,B≤10^{1000}
0≤A,B≤101000
题解
更相减损法大致思路:
对于 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(a−b,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;
}