POJ 3101 Astronomy 解题报告(大数乘法+分数最小公倍数)

博客讲述了如何使用Java的大数运算解决POJ 3101天文问题,即找出n个行星周期的最小公共倍数以使它们在同一直线上。博主首先介绍了问题背景和常规解法,然后通过求分数最小公倍数的方法来找到最短时间,并讨论了大数乘法在处理大数据时的重要性。最终分享了一段优化后的代码,虽然速度稍慢但具有更好的可读性。
摘要由CSDN通过智能技术生成

    题目大意:给出n的行星的周期,问n个行星在一条直线上的周期。

    解题报告:懒……就直接用Java大数。当然,时间垫底

import java.math.BigInteger;
import java.util.Scanner;

public class Main {
	static int[] a = new int[1010];
	static Scanner cin = new Scanner(System.in);
	
	public static void main(String[] args) {
		
		int Max=0;
		int pos=-1;
		int pos2=-2;
		int n=cin.nextInt();
		for(int i=0;i<n;i++)
		{
			a[i]=cin.nextInt();
			if(a[i]>Max)
			{
				Max=a[i];
				pos2=pos;
				pos=i;
			}
		}
		
		BigInteger p = new BigInteger(Max+"");
		BigInteger q;
		if(pos2!=-1)
			q = new BigInteger(Max-a[pos2]+"");
		else
			q = new BigInteger(Max-a[1]+"");
		
		for(int i=0;i<n;i++) if(a[i]!=Max)
		{
			p=lcm(p,new BigInteger(a[i]+""));
			q=gcd(q,new BigInteger(Max-a[i]+""));
		}
		
		q=q.multiply(new BigInteger("2"));
		BigInteger c=gcd(p,q);
		q=q.divide(c);
		p=p.divide(c);
		System.out.println(p+" "+q);
	}
	
	static BigInteger gcd(BigInteger a,BigInteger b)
	{
		if(b.equals(BigInteger.ZERO))
			return a;
		else
			return gcd(b,a.mod(b));
	}
	
	static BigInteger lcm(BigInteger a,BigInteger b)
	{
		return a.divide(gcd(a,b)).multiply(b);
	}
}


    当然,常规解法应该是这样。列出公式。假设行星1的周期是t1,行星2的周期是t2,在时间T时两行星在一条直线上,必然有:

    T*(L/t1-L/t2)=0.5*L*m,m是整数。如果要求两行星在一条直线上的最短时间,必然满足m=1。对于其他任意行星都要满足该式。

    当然,以行星1为基准,如果行星3与行星1在一条直线上,那么行星3和行星1也在一条直线上。我们可以求得T,使得

    T*(1/t1-1/ti)=0.5 对于所有行星的行星都满足。2T即为所有的(1/t1-1/ti)的最小公倍数。

    分数的最小公倍数,大家可以自己百度。结论是:分子是所有分母的最小公倍数,分母是所有分子的最大公约数。

    因为有大数据,所以用到大数乘法。经过多次优化,下面的代码在POJ上是32MS,排名第3哈哈。不过事先是把素数打表的……

#include <cstdio>
#include <cstring>
using namespace std;
#include <algorithm>

int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}

int fab(int a)
{
    return a<0?-a:a;
}

const int maxn=10001;
int num[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997,1009,1013,1019,1021,1031,1033,1039,1049,1051,1061,1063,1069,1087,1091,1093,1097,1103,1109,1117,1123,1129,1151,1153,1163,1171,1181,1187,1193,1201,1213,1217,1223,1229,1231,1237,1249,1259,1277,1279,1283,1289,1291,1297,1301,1303,1307,1319,1321,1327,1361,1367,1373,1381,1399,1409,1423,1427,1429,1433,1439,1447,1451,1453,1459,14
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值