poj 3101 大整数最小公倍数+欧几里得

27 篇文章 0 订阅
12 篇文章 1 订阅

#include <iostream>
#include <cstring>
#include <cstdio>
#include <math.h>
#include <cstdlib>
using namespace std;
#define ll long long
#define N 1000
#define M 10000
int t[N+5];
int c[M+5];
int res[M+5];
int n;
int prime[M],vis[M],cnt;
int gcd(int a,int b)
{
	return b==0?a:gcd(b,a%b);
}

void cal(int s)
{
	for(int i=0;i<cnt && s>1;++i)
		if(s%prime[i]==0)
		{
			int k=0;
			while(s%prime[i]==0)
			{
				s/=prime[i];
				k++;
			}
			if(k>c[prime[i]])
				c[prime[i]]=k;
		}
}
void init(int n)
{
	int m=sqrt(n+0.5);
	cnt=0;
	for(int i=2;i<=m;++i)
		if(!vis[i])
		{
			for(int j=i*i;j<=n;j+=i)
				vis[j]=1;
		}
	for(int i=2;i<=n;++i)
		if(!vis[i])
			prime[cnt++]=i;
}
int main ()
{
	init(M);
	while(scanf("%d",&n)!=EOF)
	{
		for(int i=1;i<=n;++i)
			scanf("%d",&t[i]);
		memset(c,0,sizeof(c));

		int nn=0;
		for(int i=2;i<=n;++i)
		{
			int b=t[i]*t[1];
			int a=abs(t[i]-t[1])<<1;
			int d=gcd(a,b);

			a/=d; // 分数化简
			b/=d;
			nn=gcd(a,nn); // 分母部分不断求最大公约数
			cal(b);
		}

		memset(res,0,sizeof(res));
		res[1]=1;
		
		// 压4位的高精度大整数乘法
		for(int i=1;i<=M;++i)
			for(int j=1;j<=c[i];++j)
			{
				int temp=0;
				for(int k=1;k<=N;++k)
				{
					res[k]=res[k]*i+temp;
					temp=res[k]/M;
					res[k]%=M;
				}
			}
		int index=N;
		for( ; res[index]==0 ;--index) ;
		printf("%d",res[index--]);
		for(;index>=1;--index)
			printf("%04d",res[index]);
		printf(" %d\n",nn);
	}
	return 0;
}

1. 每两个星球 i , j 的时间间隔为 0.5L/abs(1/ti - 1/tj) ,化简: ti * tj /  2*abs(ti - tj) ,即我们只要满足每两个的表达式为整数就可以

2.其他的每个星球都与第一个星球的时间间隔为整数,他们的时间间隔也为整数,所以就不用枚举 n*n 次 , O(n) 就好

3. 令 b=ti*tj , a=2*abs(ti-tj) ,满足每个 b/a 都为整数 ,注意 b和a 可能不是最简分数,要化简, ans 的分子部分是所有 b 的最小公倍数 ,ans 的分母是所有a的最大公约数



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值