poj 3101 Astronomy (GCD LCM 高精度)

题目链接:http://poj.org/problem?id=3101

大致题意:一个恒星系统中有n(2 ≤ n ≤ 1 000)颗行星,告诉你它们的运转周期Ti(1 ≤ ti ≤ 10 000),求他们能够同线的最小周期,表示形式是:分子 分母

Time Limit: 2000MS Memory Limit: 65536K

样例:

Sample Input

3
6 2 3

Sample Output

3 1

                               

 

思路:仔细看图就知道任意两颗行星共线,则 x/t1 - x/t2 = 0 mod (1/2),运行距离差为半个周长的整数倍即可,整理得到(t2-t1)*x/(t1*t2) = 0 mod (1/2),这样的方程可以列n*(n-1)/2个。但不需要这么多,我们都以第一颗行星作为标尺 x/t1 - x/t2 = 0 mod(1/2) ,x/t1 - x/t3 = 0 mod(1/2),两式相减得到 x/t3 - x/t2 = 0 mod(1/2)

所以只需要这n-1个公式成立即可。再将上述式子变形:x*(2/t1-2/t2)=0 mod 1,那么问题就转化为求(2/t1-2/ti) (2 ≤ i ≤ n)中分母的最小公倍数和分子的最大公约数,最小公倍数的答案的分子,最大公约数是答案的分母。想不通的找几个分数通分一下就懂了。

一开始用的是简单求lcm,提交WA了。回头看看数据范围,1 ≤ ti ≤ 10 000,考虑极限情况,如果把10000以内的质数大小都看作是10^4 那么1000个数的乘积就是10^4000次方。这样计算,这个题求LCM还需要高精度,求的最大公约数就不用了,最大公约数明显小与10000。1.可以用JAVA大数直接算。 2.LCM(a,b)=∏ (pi^max(ai,bi)),把a,b 质因数分解 分别表示成∏ (pi^ai)和∏ (pi^bi)的形式,如果a或b中一个有质因子p一个没有,则没有质因子p的指数设成0,这样就能保证表示的一致性。这样就能把最小公倍数以质因数分解的形式表示了。还原成大数可以用一个数组表示,数组中每个数占4-5位。

这里有一个细节要注意,由于最大公倍数是由数组表示的,在分子和分母约分的时候会很困难,所以我们求(2/t1-2/ti)的时候先对分子和分母进行约分,这样就能够保证最后分子分母互质。

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 int prime[5000],head,Div[5000];
 5 bool isprime[10005];
 6 void getPrime(){
 7     head=0;
 8     memset(isprime,0,sizeof(isprime));
 9     for(int i=2;i<10000;i++)if(!isprime[i]){
10         prime[head++]=i;
11         for(int j=2*i;j<10000;j+=i){
12             isprime[j]=true;
13         }
14     }
15 }
16 int gcd(int a,int b){
17     if(b==0){
18         return a;
19     }
20     return gcd(b,a%b);
21 }
22 int lcm(int a,int b){
23     return a*b/gcd(a,b);
24 }
25 const int MAXNUM=1005;
26 int d[MAXNUM],den[MAXNUM];
27 int main(){
28     int n,i,j,k,f,numerator;
29     getPrime();
30     while(~scanf("%d",&n)){
31         numerator=0;
32         memset(Div,0,sizeof(Div));
33         memset(den,0,sizeof(den));
34         den[0]=1;
35         for(i=0;i<n;i++){
36             scanf("%d",&d[i]);
37         }
38         for(i=1;i<n;i++){
39                 if(d[i]==d[0])continue;
40                 int LCM=lcm(d[i],d[0]);  //求分母
41                 f=2*(int)fabs(LCM/d[i]-LCM/d[0]);  //求分子
42                 int temp=gcd(LCM,f);
43                 LCM/=temp;  //分子分母约分
44                 f/=temp;
45                 numerator=gcd(numerator,f);  //求最大公约数
46                 for(j=0;j<head;j++){  //分解质因数
47                     int t=0;
48                     while(LCM%prime[j]==0){
49                         t++;LCM/=prime[j];
50                     }
51                     if(Div[j]<t)Div[j]=t;  //记录较大的指数
52                     if(LCM==1)break;
53                 }
54         }
55         for(i=0;i<head;i++){
56             for(j=0;j<Div[i];j++){
57                 int temp=0;
58                 for(k=0;k<MAXNUM;k++){  //大数表示
59                     den[k]=den[k]*prime[i]+temp; 
60                     temp=den[k]/10000;
61                     den[k]%=10000;
62                     
63                 }
64             }
65         }
66         for(i=MAXNUM-1;i>=0;i--)if(den[i]!=0)break;
67         printf("%d",den[i]);
68         while(i>0)printf("%04d",den[--i]);  //由于表示的4位数可能有前头0,所以强制输出4位
69         printf(" %d\n",numerator);
70     }
71     return 0;
72 }

 

 

转载于:https://www.cnblogs.com/mcflurry/archive/2012/07/30/2614991.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值