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

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[N];
	static int primes[]=new int[N];
	static int e1[]=new int[N];
	static int e2[]=new int[N];
	static int e3[]=new int[N];
	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


你可能感兴趣的:(其他OJ习题,ACM/ICPC区域赛真题,数学——数论)