poj 2773

来源:互联网 发布:会员视频源码 编辑:程序博客网 时间:2024/06/07 00:45

(二分+容斥原理)
题意:求第k(1k100000000)个与m(1m1000000)互质的数字是多少?

思路:二分k,每次找出小于k且与m互质的数字有多少个,多了就把k变小,少了就把k放大。这里顺便复习下容斥原理的两种写法:迭代法和递归法。(一定一定注意哪些地方有可能爆int!)

代码:

#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#define LL long longusing namespace std;const double eps = 1e-8;bool vis[100100];LL fac[100100];/*LL solve(LL x, LL cnt){    LL ret = 0;    for(LL i=1; i<(1<<cnt); i++){        LL bits = 0, mul = 1;        for(LL j=0; j<cnt; j++)if(i&(1<<j)){            bits ++; mul *= fac[j];        }        if(bits&1) ret += x/mul;        else ret -= x/mul;    }    return x - ret;}*/LL solve(LL m, LL x, LL cnt){    LL ret = 0;    for(int i=x; i<cnt; i++){        ret += m/fac[i] - solve(m/fac[i], i+1, cnt);    }    return ret;}int main(){    //freopen("test.txt","r",stdin);    LL m, k;    while(scanf("%lld%lld",&m,&k) == 2){        LL cnt = 0, tm = m;        for(LL i=2; i*i<=tm; i++) if(tm%i == 0){            fac[cnt++] = i;            while(tm%i == 0) tm /= i;        }        if(tm > 1) fac[cnt++] = tm;        LL l = 1, r = 1000000000000;        while(l < r){            LL mid = (r-l)/2 + l;            //if(solve(mid, cnt) >= k) r = mid;            if(mid - solve(mid, 0, cnt) >= k) r = mid;            else l = mid + 1;        }        printf("%lld\n",l);    }    return 0;}