这题主要思路是先确定这两个数是由那几个质数组成,然后通过二分法进行搜索,利用容斥原理检查搜索到的数中所包含的符合条件的数是不是大于等于k,这样搜索下去到最后l也可以说是r+1就会记录最小的那个点,那个点所对应的符合条件的数就是k,所以直接输出那一点的值就行了。代码中还有更详细一点的注释。
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
using namespace std;
const int N=1000005;
const __int64 INF=(__int64)1<<62;
bool prime[N];
__int64 p[N];
__int64 f[N];
__int64 k,cnt,num,ans,n,m,K;
void isprime()//判断素数,将素数存在数组p中
{
k=0;
int i,j;
memset(prime,true,sizeof(prime));
for(i=2; i<N; i++) //只搜寻到10^6就够用的原因是,n要被分解成质数的话,比根号n还大的质数最多就一个,那直接看分解完之后还剩下什么就行
{
if(prime[i])
{
p[k++]=i;
for(j=i+i; j<N; j+=i)
{
prime[j]=false;
}
}
}
}
void Solve(__int64 m,__int64 n)//在已知素数组中求能被m,n整除的素数放在数组f中
{
cnt=0;
__int64 i;
for(i=0; p[i]*p[i]<=n; i++)
{
if(n%p[i]==0)
{
f[cnt++]=p[i];
while(n%p[i]==0) n/=p[i];
}
}
if(n>1)
f[cnt++]=n;
for(i=0; p[i]*p[i]<=m; i++)
{
if(m%p[i]==0)
{
f[cnt++]=p[i];
while(m%p[i]==0) m/=p[i];
}
}
if(m>1)
f[cnt++]=m;
}
void dfs(__int64 k,__int64 t,__int64 s,__int64 n) //利用容斥原理求可以由公因子组成的数的个数,
{
if(k==num)
{
if(t&1) ans+=n/s;
else if(t!=0) ans-=n/s;
return;
}
dfs(k+1,t,s,n);
dfs(k+1,t+1,s*f[k],n);
}
__int64 Binary() //二分查找
{
__int64 l=1,r=INF,mid;
while(l<=r)
{
mid=(l+r)/2;
ans=0;
dfs(0,0,1,mid);
if((mid-ans)>=K)
{
r=mid-1;
}
else
l=mid+1;
}
return l;
}
int main()
{
isprime();
__int64 t,ct,tt=1;
scanf("%I64d",&t);
while(t--)
{
scanf("%I64d%I64d%I64d",&m,&n,&K);
printf("Case %d: ",tt++);
if(n==1&&m==1)
{
printf("%I64d\n",k);
continue;
}
Solve(m,n);
sort(f,f+cnt);//排序
num=1;
for(__int64 i=1; i<cnt; i++)//去除重复的情况
{
if(f[i]!=f[i-1])
{
f[num++]=f[i];
}
}
ct=num; //记录下两者的因素数总数
printf("%I64d\n",Binary());
}
return 0;
}