hdu3388 Coprime 二分+容斥原理

Description

Please write a program to calculate the k-th positive integer that is coprime with m and n simultaneously. A is coprime with B when their greatest common divisor is 1.

Input

The first line contains one integer T representing the number of test cases. 
For each case, there's one line containing three integers m, n and k (0 < m, n, k <= 10^9).

Output

For each test case, in one line print the case number and the k-th positive integer that is coprime with m and n. 
Please follow the format of the sample output.

Sample Input

3
6 9 1
6 9 2
6 9 3

Sample Output

Case 1: 1
Case 2: 5
Case 3: 7

这题主要思路是先确定这两个数是由那几个质数组成,然后通过二分法进行搜索,利用容斥原理检查搜索到的数中所包含的符合条件的数是不是大于等于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;  
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值