bzoj1876: [SDOI2009]SuperGCD

本文深入探讨了一种高精度最大公约数(GCD)算法的实现细节,通过使用更相减损法并进行优化,解决了当两个数相差极大时算法效率低下的问题。文中提供了完整的代码示例及解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接

  http://www.lydsy.com/JudgeOnline/problem.php?id=1876

题解

  很显然是高精度gcd。。。

  从一开始我就是用的更相减损,好多人都坑我说:更相减损的复杂度大约是log的吧。我就没思考地信了。。。。但是所有点T了之后我才开始反思,有个很简单的例子就是,gcd(10^20,1)=gcd(10^20-1,1)=gcd(10^20-2,1)=gcd(10^20-3,1)...,这tm不是O(N)的么!

  考虑慢在哪里,如果a和b差的太多,那就要不断地减去b直到a<b。可以让b乘上10的某个次幂而使这个过程加速,而b乘上10的几次幂就是把这个数向左移多少位。移动的位数我就让它等于a的长度-b的长度-1。压位可过。

代码

//高精度 + 更相减损 
#include <cstdio>
#include <algorithm>
#include <cstring>
#define maxn 10010
#define ll long long
using namespace std;
long long a[maxn], b[maxn];
char s[maxn];
void input()
{
	long long i;
	scanf("%s",s+1);
	a[0]=strlen(s+1);
	for(i=1;i<=a[0];i++)a[(a[0]-i)/9+1]=(a[(a[0]-i)/9+1]*10+s[i]-48);
	a[0]=(a[0]/9)+(a[0]%9!=0);
	scanf("%s",s+1);
	b[0]=strlen(s+1);
	for(i=1;i<=b[0];i++)b[(b[0]-i)/9+1]=(b[(b[0]-i)/9+1]*10+s[i]-48);
	b[0]=(b[0]/9)+(b[0]%9!=0);
}
inline bool cmp(long long *x, long long *y)
{
	if(x[0]<y[0])return true;
	if(x[0]>y[0])return false;
	for(long long i=x[0];i;i--)
		if(x[i]<y[i])return true;
		else if(x[i]>y[i])return false;
	return false;
}
void show(long long *x)
{
	long long i;
	printf("%lld",x[x[0]]);
	for(i=x[0]-1;i;i--)
	{
		if(x[i]<100000000)printf("0");
		if(x[i]<10000000)printf("0");
		if(x[i]<1000000)printf("0");
		if(x[i]<100000)printf("0");
		if(x[i]<10000)printf("0");
		if(x[i]<1000)printf("0");
		if(x[i]<100)printf("0");
		if(x[i]<10)printf("0");
		printf("%lld",x[i]);
	}
}
void gcd(long long *x, long long *y)
{
	long long i, t, a;
	while(1)
	{
		if(cmp(x,y))swap(x,y);
		if(y[0]==0){show(x);return;}
		t=max((ll)0,x[0]-y[0]-1);
		a=(x[y[0]+t]+x[y[0]+t+1]*1000000000)/(y[y[0]]+1);
		if(!a)a=1;
		for(i=1;i<=y[0];i++)x[i+t]-=a*y[i];
		for(i=1;i<x[0];i++)
			if(x[i]<0)
				x[i+1]+=x[i]/1000000000-(x[i]%1000000000!=0),
				x[i]=(x[i]%1000000000+1000000000)%1000000000;
		for(i=x[0];x[i]==0 and i;i--)x[0]--;
	}
}
int main()
{
	input();
	gcd(a,b);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值