您的位置:首页 > 理论基础 > 计算机网络

HDU 5447 Good Numbers (2015年长春赛区网络赛K题)

2015-09-17 19:47 676 查看
1.题目描述:点击打开链接

2.解题思路:本题利用唯一分解定理+gcd解决。这是我第一次用Java写题,忙了一下午终于通过了,真是太不容易了==。本题实际上就是把k1,k2分解后,把所有素因子的指数相乘就是答案。然而,k1,k2的范围太大了,高达10^24,为了方便使用大整数,直接上Java。

接下来就是考虑如何高效分解k1,k2了,注意到题目中给了一个条件:k1,k2的最大的素因子是相同的,第2大的素因子一定不同。这就提示我们可以考虑通过gcd来求解。假设gcd值是g。可以证明,如果把g中小于10^6的素因子全部分解掉,而且剩下部分仍然大于10^6的话,那么剩余部分一定是第1大素因子的1次幂,或2次幂,或3次幂。首先,g中一定包含第一大素因子,而且下一个包含的素因子至多是第3大素数,不妨设第一大素数为p1,第二大素数在k1中是p2,第三大素数是p3。那么如果g中含有p1的平方或立方,此时p3至多是10^6,然而10^6肯定是合数,因此p3一定早就被分解掉了。因此g中最后剩下的一定是p1^m。不难通过尝试求出p1。

求出p1后,把p1从k1,k2中除干净,并对k1,k2进行分解,那么不难证明,如果剩下的部分大于10^6,则一定是他们的第二大素数的2次幂或者是第二大素数和第3大素数,第4大素数等的乘积。证明方法同上。但是只有当第2大素数是2次幂时候才对答案有贡献,否则不用考虑它具体是多少,而且只要第2大素数是2次幂,那么第3大素数也一定小于10^6,在分解时候就能被找到。这样,算出大素数对应的幂次之后,小素数的幂次在分解时候就能顺便得到,累乘ans即可。

3.代码:

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

public class Main{
	final static int N=1000000+10;
	static int vis[]=new int
;
	static int primes[]=new int
;
	static int e1[]=new int
;
	static int e2[]=new int
;
	static int e3[]=new int
;
	static int v1[]=new int[100];
	static int v2[]=new int[100];
	static int v3[]=new int[100];
	static int c1,c2,c3;
	static int idx;
	public static void main(String[] args)
	{
		BigInteger k1,k2;
		int T;
		sieve();
		BigInteger bound=BigInteger.valueOf(1000000);//最大界限
		Scanner in=new Scanner(System.in);
		T=in.nextInt();
		while(T-->0)
		{
			init();
			k1=in.nextBigInteger();
			k2=in.nextBigInteger();
			BigInteger g=k1.gcd(k2);
			k1=factor(v1,e1,k1);//v数组记录素因子的下标,e数组记录素因子的幂次
			k2=factor(v2,e2,k2);
			g=factor(v3,e3,g);
			
			long r1=1,r2=1;
			if(g.compareTo(bound)==1)
			{
				if(is_ok(2,g))
					g=getRoot(2,g);//找到第1大素数
				else if(is_ok(3,g))
					g=getRoot(3,g);
			}
			if(k1.compareTo(bound)==1)
			{
				int t1=0;
				while(k1.mod(g).equals(BigInteger.ZERO))//将第1大素数除干净
				{
					k1=k1.divide(g);
					t1++;
				}
				r1*=t1;
				if(k1.compareTo(bound)==1&&is_ok(2,k1))//如果剩下部分仍然大于10^6且是某个素数的2次幂,那么该素数就是第二大素数,否则,后面所有大素数都不必考虑
					r1*=2;
			}
			if(k2.compareTo(bound)==1)
			{
				int t2=0;
				while(k2.mod(g).equals(BigInteger.ZERO))
				{
					k2=k2.divide(g);
					t2++;
				}
				r2*=t2;
				if(k2.compareTo(bound)==1&&is_ok(2,k2))
					r2*=2;
			}
			for(int i=0;i<100;i++)//累乘分解后的幂次
			{
				int id=v1[i];
				if(id<0)break;
				r1*=e1[id];
			}
			for(int i=0;i<100;i++)
			{
				int id=v2[i];
				if(id<0)break;
				r2*=e2[id];
			}
			System.out.println(r1+" "+r2);
		}
		
	}
	
	
	static void sieve()
	{
		Arrays.fill(vis, 0);
		idx=0;
		int m=(int)Math.sqrt(N);
		for(int i=2;i<=m;i++)
			if(vis[i]==0)
				for(int j=i*i;j<N;j+=i)
					vis[j]=1;
		for(int i=2;i<N;i++)
			if(vis[i]==0)
				primes[idx++]=i;
	}
	
	static void init()
	{
		Arrays.fill(e1, 0);
		Arrays.fill(e2, 0);
		Arrays.fill(e3, 0);
		Arrays.fill(v1, -1);
		Arrays.fill(v2, -1);
		Arrays.fill(v3, -1);
	}
	
	static boolean is_ok(int d,BigInteger a)//如果a是某个数的d次幂
	{
		BigInteger t,mul;
		if(d==2)
			t=BigInteger.valueOf((long)Math.sqrt(a.doubleValue()));
		else t=BigInteger.valueOf((long)Math.pow(a.doubleValue(), 1.0/3));
		mul=BigInteger.ONE;
		for(int i=0;i<d;i++)mul=mul.multiply(t);
		if(a.equals(mul))return true;
		t=t.add(BigInteger.ONE);
		mul=BigInteger.ONE;
		for(int i=0;i<d;i++)mul=mul.multiply(t);
		if(a.equals(mul))return true;
		return false;
	}
	
	static BigInteger getRoot(int d,BigInteger a)//求a的d次方根
	{
		BigInteger t,mul;
		if(d==2)t=BigInteger.valueOf((long)Math.sqrt(a.doubleValue()));
		else t=BigInteger.valueOf((long)Math.pow(a.doubleValue(), 1.0/3));
		mul=BigInteger.ONE;
		for(int i=0;i<d;i++) mul=mul.multiply(t);
		if(a.equals(mul))return t;
		else return t.add(BigInteger.ONE);
	}
	static BigInteger factor(int v[],int e[],BigInteger a)
	{
		int c=0;
		long m=(long)Math.sqrt(a.doubleValue());
		for(int i=0;i<idx&&primes[i]<=m;i++)
		{
			BigInteger j=BigInteger.valueOf(primes[i]);
			if(a.mod(j)==BigInteger.ZERO)
			{
				e[i]=0;
				v[c++]=i;
				while(a.mod(j)==BigInteger.ZERO)
				{
					e[i]++;
					a=a.divide(j);
				}
			}
		}
		return a;
	}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: