HDU, 5447 Good Numbers

1 篇文章 0 订阅

题意:假设有一个数K,如果有个小于等于K的数n和K的所有质因子相同,那么他们就是一对good numbers,现在给你K1和K2,他们的范围是1到10^24,让你求他们俩的各自的good number的个数。但是K1和K2存在一个非常有趣的关系,就是他们俩的最大质因子一定是相同的,两个第二大的质因子一定不同。

思路:(思路比较长,可以直接看代码)__int64的最大范围是2^64,大概也就是10^19,要比输入数字的取值范围小,所以如果要用C++来写,那么只能自己写个加减乘除求余了。。。于是写了半天还是放弃C++用java写了。说一下解法的思路:

求good numbers 数的思路:找到所有good number的质因数,并记录每个相同质因数的个数。因为K1和它的good number的所有质因子是相同的,那么利用排列组合的思想必然每个质因数都要取,然后每种的数量相乘即可。例如12的goodnumber是6和12,因为12分解质数以后是2*2*3,那么找good number取2的质因数时取一个2和取两个2的情况,取3的质因数时只有取一个3的情况,总情况就是2*1=2了。那么现在最大的问题就是分解质因数了:

首先由于输入的数字最大为10^24,那么它的最大素数因子最大也只能是10^23这个范围,它第二小的素数因子最大只能是10^12不到,其他素数一定在10^6范围之内了,那么可以用筛法先打一个表,然后求出K1和K2的最大公约数G,由于G的质因子只有1个可能在10^6以上,在G除掉所有10^6以内所有素数后,G只能是这个最大质数或者这个最大质数的平方或三次方。分解掉最大因数后,第二大因数只能在10^12以内,那么判断它是不是素数就很简单了,只要10^6内的素数都不能除尽就一定是素数。所以先求最大公约数,遍历10^6以内素数,能除尽就相除,得到最大质因数的指数,然后看它是几次方,然后K1K2分别除掉这个数,剩下的分解就很简单了。

代码:

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

class prime			//存所有质数的类
{
	public final static int N=1000000;
	public static int[] IsNotPrime = new int[N+10];
	public static Vector<Integer> Prime=new Vector<Integer>();
	public static int prime_num=0;
	public prime()
	{
		Arrays.fill(IsNotPrime, 0);
		for(int i=2;i<=N;i++)		//利用快速筛法求出所有质数,并存在一个vector里
		{
			if(IsNotPrime[i]==0)
			{
				Prime.add(i);
				prime_num++;
			}
			for(int j=0;j<prime_num&&i*Prime.elementAt(j)<=N;j++)
			{
				IsNotPrime[i*Prime.elementAt(j)]=1;
				if(i%Prime.elementAt(j)==0)
					break;
			}
		}
	}
	public static int value(int i)		//返回第i+1个质数
	{
		return Prime.elementAt(i);
	}
}
public class Main {
	@SuppressWarnings("static-access")
	public static void main(String args[])
	{
		prime P = new prime();				//初始化打表
		BigInteger k[] = new BigInteger[3];		//分别存K1、K2和它们的最大公因数G
		Scanner in = new Scanner(System.in);
		int T;
		T=in.nextInt();
		while(T-->0)
		{
			k[0]=in.nextBigInteger();k[1]=in.nextBigInteger();
			k[2]=k[0].gcd(k[1]);
			long ans[]=new long[3];
			Arrays.fill(ans, 1);
			for(int i=0;i<3;i++)		//遍历把所有10^6以内的质数因子情况,同时把G摘成最大公因数的指数
			{
				ans[i]=1;
				for(int j=0;j<P.prime_num;j++)
				{
					if(k[i].mod(BigInteger.valueOf(P.value(j))).equals(BigInteger.ZERO))
					{
						long c=0;
						while(k[i].mod(BigInteger.valueOf(P.value(j))).equals(BigInteger.ZERO))
						{
							c++;
							k[i]=k[i].divide(BigInteger.valueOf(P.value(j)));
						}
						ans[i]*=c;
					}
				}
			}
			if(k[2].compareTo(BigInteger.valueOf(P.N))==1)
			{
				long n = figure(k[2]);		//求G是最大质因数的多少次方
				BigInteger g;
				if(n==1)
					g=k[2];
				else if(n==2)
				{
					g=BigInteger.valueOf((long)Math.sqrt(k[2].doubleValue()));
					if(!k[2].equals(g.multiply(g)))
						k[2]=k[2].add(BigInteger.ONE);
				}
				else
				{
					g=BigInteger.valueOf((long)Math.pow(k[2].doubleValue(), 1.0/3));
					if(!k[2].equals(g.multiply(g.multiply(g))))
						g=g.add(BigInteger.ONE);
				}
				for(int i=0;i<2;i++)
				{
					long c=0;
					while(k[i].mod(g).equals(BigInteger.ZERO))		//求K1、K2第二大公因数的次方数
					{
						c++;
						k[i]=k[i].divide(g);
					}
					ans[i]*=c;
					if(k[i].compareTo(BigInteger.valueOf(P.N))==1)
						ans[i]*=figure(k[i]);
				}
			}
			System.out.println(ans[0]+" "+ans[1]);
		}
		in.close();
	}
	public static long figure(BigInteger temp)
	{
		if(temp.equals(BigInteger.ONE))
			return 1;
		BigInteger t=BigInteger.valueOf((long)Math.sqrt(temp.doubleValue()));
		if(temp.equals(t.multiply(t)))
			return 2;
		t.add(BigInteger.ONE);
		if(temp.equals(t.multiply(t)))
			return 2;
		t=BigInteger.valueOf((long)Math.pow(temp.doubleValue(), 1.0/3));
		if(temp.equals(t.multiply(t.multiply(t))))
			return 3;
		t.add(BigInteger.ONE);
		if(temp.equals(t.multiply(t.multiply(t))))
			return 3;
		return 1;
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值