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<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;
}
}