hdu 3388 Coprime 容斥原理 二分查找

Coprime

刚开始不知道用二分,因为没有发现序列单调不下降的性质;
留意二分查找需找到下界。
二分查找起点的右边界取m*n是不够的,实际查找到的结果可能远大于该值。

/** Aug 27, 2015 9:25:32 PM
 * PrjName:hdu3388
 * @author Semprathlon
 */
import java.io.*;
import java.util.*;
public class Main {

    /**
     * @param args
     */
    static Vector<Integer> v1=new Vector<Integer>();
    static Vector<Integer> v2=new Vector<Integer>();
    static HashSet<Integer> st=new HashSet<Integer>();
    static Integer[] fac=new Integer[0];
    static Vector<Integer> get_prime_factor(int n){
        Vector<Integer> res=new Vector<Integer>();
        res.clear();
        for(int i=2;i*i<=n;i++)
            if (n%i==0){
                res.add(i);
                while(n%i==0)
                    n/=i;
            }
        if (n>1) res.add(n);
        return res;
    }
    static long check(long n){
        long res=0L;
        int m=fac.length;
        for(int i=1;i<(1L<<m);i++){
            long tmp=1L;
            boolean tag=false;
            for(int j=0;j<m;j++)
                if (((1L<<j)&i)>0L){
                    tmp*=fac[j].longValue();
                    tag^=true;
                }
            res+=tag?n/tmp:-n/tmp;
        }
        return n-res;
    }
    static long bisearch(long low,long high,long key){
        long l=low,r=high,mid;
        while(l<r){
            mid=(l+r)>>1;
            if (check(mid)>=key)
                r=mid;
            else
                l=mid+1;
        }
        return l;
    }
    public static void main(String[] args) throws IOException{
        // TODO Auto-generated method stub
        InputReader in=new InputReader(System.in);
        PrintWriter out=new PrintWriter(System.out);
        int T=in.nextInt(),cas=0;
        while(T-->0){
            int m=in.nextInt();
            int n=in.nextInt();
            int k=in.nextInt();
            v1=get_prime_factor(m);
            v2=get_prime_factor(n);
            st.clear();
            for(Integer e:v1.toArray(new Integer[0]))
                st.add(e);
            for(Integer e:v2.toArray(new Integer[0]))
                st.add(e);
            fac=st.toArray(new Integer[0]);
            out.println("Case "+(++cas)+": "+bisearch(1, 0x3f3f3f3f3f3f3f3fL, k));
        }
        out.flush();
        out.close();
    }

}

较为神奇的是,把以上代码的check()函数(实现容斥原理的计算)替换为以下实现后,效率大有提升。

static long check(long n,int low){
        long sum=0L;
        for(int i=low;i<fac.length;i++)
            sum+=n/fac[i].longValue()-check(n/fac[i].longValue(),i+1);
        return sum;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值