题意:假设有一个数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;
}
}