POJ3101 Astronomy——高精度+分解质因子法求GCD和LCM——Pku3101

经典的求分数GCD和LCM的题目。方法:分别求出每个行星对于第一颗行星的相对速度,设其为ai/bi,那么答案就是乘上的一个最小的分数使得所有ai/bi与它相乘之后都为整数。那么这个分数就是:

(所有bi的LCM)

--------------

(所有ai的GCD)

用分解质因子的方法就可以求出这个分数了。注意要用高精度。

代码如下:

Program Astronomy;//By_Thispoet
Const
	maxn=10000;
Type
	arr=array[0..maxn]of Longint;
Var
	i,j,k,m,n,tmp				:Longint;
	t,fz,fm						:Array[0..maxn]of Longint;
	map,num						:Array[0..maxn]of Longint;
	prime						:Array[1..maxn*10]of Boolean;
	ans							:arr;
	flag						:Boolean;


Function Max(i,j:Longint):Longint;
begin
	if i>j then exit(i);exit(j);
end;


Function Min(i,j:Longint):Longint;
begin
	if i<j then exit(i);exit(j);
end;


Function Gcd(i,j:Longint):Longint;
begin
	if j=0 then exit(i);
	exit(Gcd(j,i mod j));
end;


Procedure Printf(i:Longint);
begin
	if i>=1000 then write(i) else
		if i>=100 then
			begin
				write(0);
				write(i);
			end else if i>=10 then
				begin
					write('00');
					write(i);
				end else
					begin
						write('000');
						write(i);
					end;
end;


Procedure Multiply(i:Longint;var p:arr);
var j,k:Longint;
begin

	for j:=1 to p[0] do
		p[j]:=p[j]*i;
	j:=1;
	while j<=p[0] do
		begin
			inc(p[j+1],p[j] div 10000);
			p[j]:=p[j] mod 10000;
			if p[p[0]+1]>0 then inc(p[0]);
			inc(j);
		end;

end;


Procedure Prime_Prepare;
begin
	prime[1]:=false;
	for i:=2 to maxn do
		if prime[i] then
			begin
				inc(map[0]);
				map[map[0]]:=i;
				j:=i<<1;
				while j<=maxn do
					begin
						prime[j]:=false;
						inc(j,i);
					end;
			end;
end;


BEGIN

	readln(n);
	fillchar(prime,sizeof(prime),1);
	Prime_Prepare;
	while not eof do
		begin
			flag:=false;

			t[0]:=0;
			for i:=1 to n do read(t[i]);

			for i:=2 to n do
				begin
					fz[i]:=t[i-1]*t[i];
					fm[i]:=abs(t[i-1]-t[i]);
					if fm[i]<>0 then
						begin
							tmp:=Gcd(fz[i],fm[i]);
							fz[i]:=fz[i] div tmp;
							fm[i]:=fm[i] div tmp;
						end;
				end;

			fillchar(num,sizeof(num),0);
			ans[0]:=1;ans[1]:=1;

			for i:=2 to n do
				begin
					if fm[i]<>0 then
						begin
							for j:=1 to map[0] do
								if fz[i]<map[j] then break else
									begin
										if fz[i] mod map[j]=0 then
											begin
												tmp:=0;
												while fz[i] mod map[j]=0 do
													begin
														inc(tmp);
														fz[i]:=fz[i] div map[j];
													end;
												num[j]:=Max(num[j],tmp);
											end;
									end;
						end;
				end;

			for i:=1 to map[0] do
					if num[i]>0 then
						begin
							if (not flag)and(not odd(map[i])) then
								begin
									dec(num[i]);
									flag:=true;
								end;
							for j:=1 to num[i] do
								Multiply(map[i],ans);
						end;

			fillchar(num,sizeof(num),127);

			write(ans[ans[0]]);
			for i:=ans[0]-1 downto 1 do
				printf(ans[i]);

			write(' ');

			fillchar(ans,sizeof(ans),0);
			ans[0]:=1;ans[1]:=1;
			for i:=2 to n do
				begin
					if fm[i]<>0 then
						begin
							for j:=1 to map[0] do
									begin
										tmp:=0;
										if fm[i] mod map[j]=0 then
											begin
												while fm[i] mod map[j]=0 do
													begin
														inc(tmp);
														if tmp>=num[j] then break;
														fm[i]:=fm[i] div map[j];
													end;
											end;
										num[j]:=Min(num[j],tmp);
									end;
						end;
				end;
		
			for i:=1 to map[0] do
					if num[i]<maxint then
						begin
							for j:=1 to num[i] do
								Multiply(map[i],ans);
						end;	
			if not flag then Multiply(2,ans);
	
			write(ans[ans[0]]);
			for i:=ans[0]-1 downto 1 do
				printf(ans[i]);		
	
			writeln;
			readln(n);
			if n=0 then break;
		end;
	
END.

转载于:https://www.cnblogs.com/Thispoet/archive/2011/09/20/2182009.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值