题目传送门:https://www.luogu.org/problemnew/show/P2152
题意:
给两个正整数n,m(0 < n,m ≤ 10 ^ 10000),求n,m的最大公约数。
思路:
辗转相减法+优化。
即:对于求a,b的GCD(a,b)有:
若a为奇数,b为偶数,GCD(a,b)=GCD(a,b/2)
若a为偶数,b为奇数,GCD(a,b)=GCD(a/2,b)
若a为偶数,b为偶数,GCD(a,b)=2*GCD(a/2,b/2)
若a为奇数,b为奇数,GCD(a,b)=GCD(a-b,b) (a>b) 或 GCD(b-a,a) (b>a)
代码:
#include<cstdio>
#include<cstring>
#define R register
#define I inline
char s[10001];
int a[10001],b[10001],d[10001];
int la,lb,tot=0;
I void print(int a[10001],int p)
{
for(R int i=p;i>=1;i--)
printf("%c",a[i]+48);
}
I void chu(int a[10001],int &p)
{
memset(d,0,sizeof(d));
int r=0;
for(R int i=p;i>=1;i--)
{
r=r*10+a[i];
d[i]=(r>>1);
r&=1;
}
while(!d[p]&&p>1)
p--;
memcpy(a,d,sizeof(d));
}
I void cheng()
{
a[la+1]=0;
for(R int i=la;i>=1;i--)
{
a[i]<<=1;
a[i+1]+=a[i]/10;
a[i]%=10;
}
while(a[la+1])
la++;
}
I void jian(int a[10001],int b[10001],int &p)
{
memset(d,0,sizeof(d));
for(R int i=1;i<=p;i++)
{
if(a[i]<b[i])
{
a[i+1]--;
a[i]=a[i]+10;
}
d[i]=a[i]-b[i];
}
while(!d[p]&&p>1)
p--;
memcpy(a,d,sizeof(d));
}
I int pd()
{
if(la>lb) return 1;
if(la<lb) return 0;
for(R int i=la;i>=1;i--)
{
if(a[i]>b[i]) return 1;
if(a[i]<b[i]) return 0;
}
return 9999;
}
int main()
{
scanf("%s",s+1);
la=strlen(s+1);
for(R int i=1;i<=la;i++)
a[i]=s[la-i+1]-48;
scanf("%s",s+1);
lb=strlen(s+1);
for(R int i=1;i<=lb;i++)
b[i]=s[lb-i+1]-48;
while((!(a[1]&1))&&(!(b[1]&1)))
{
chu(a,la);
chu(b,lb);
tot++;
}
while(!(a[1]&1)) chu(a,la);
while(!(b[1]&1)) chu(b,lb);
while(pd()!=9999)
{
if(pd()) jian(a,b,la); else jian(b,a,lb);
while(!(a[1]&1)) chu(a,la);
while(!(b[1]&1)) chu(b,lb);
}
while(tot--)
cheng();
print(a,la);
}