刚开始不知道用二分,因为没有发现序列单调不下降的性质;
留意二分查找需找到下界。
二分查找起点的右边界取m*n是不够的,实际查找到的结果可能远大于该值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
|
import java.io.*; import java.util.*; public class Main {
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{ 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()函数(实现容斥原理的计算)替换为以下实现后,效率大有提升。
1 2 3 4 5 6
| 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; }
|