Coprime HDU3388(容斥原理+二分查找)

Coprime

 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

题意:

求与n,m 互质的第 k 个数。

分析:

由于m,n比较大,直接枚举出第k个和他们互质的数必然会超时(实时是时间卡的相当恶心)

我们可以通过二分找到一个最小的x,使得在x范围内的即[1,x]和m,n都互质的个数大于等于k,然后不断二分下去,这样一定会到一个时刻,二分到一个数x,在[1,x]范围内与m,n互质的数有k个,并且x恰好就是第k个数,因此这个x便是我们要找的答案

对于每次二分出来的x,我们要求[1,x]内与n,m互质的数的个数,每次利用容斥定理,记录下m,n素因子,然后二进制枚举选取的情况

我这里因为要存m,n的因子,为了去重我用了set,但是把set里的元素存回数组的时候

不能用迭代器

超时到爆炸,mb像吃了屎一样。。。。
咋改呢,不用迭代器每次把s.begin()存进去,然后erase掉begin()就过了
一开始我还以为是容斥写超时了。。

code:

#include 
using namespace std;
typedef long long ll;
const int maxn = 1e6+10;
ll fac[maxn],len;
set s;
ll n,m,k;
void divide(ll a){
    for(ll i = 2; i * i <= a; i++){
        if(a % i == 0){
            s.insert(i);
            while(a % i == 0) a /= i;
        }
    }
    if(a > 1) s.insert(a);
}
void getFac(){
    len=0;
        while(!s.empty()){
        fac[len++]=*s.begin();//就是这里让我超时到想。。。不能用迭代器
        s.erase(s.begin());
    }

}
ll RC(ll s){
    ll res = 0;
    for(ll i = 1; i < (1LL<1,cnt = 0;
        for(ll j = 0; j < len; j++){
            if(i & (1LL << j)){
                tmp *= fac[j];
                cnt++;
            }
        }
        if(cnt & 1) res += s / tmp;
        else res -= s / tmp;
    }
    return res;
}
ll solve(){
    ll l = 0,r = 1LL<<62;
    while(l <= r){
        ll mid = (l + r) / 2;
        ll ans = mid - RC(mid);
        if(ans >= k){
            r = mid - 1;
        }
        else{
            l = mid + 1;
        }
    }
    return l;
}
int main(){
    int T,cas = 0;
    scanf("%d",&T);
    while(T--){
        scanf("%lld%lld%lld",&m,&n,&k);
        printf("Case %d: ",++cas);
        if(k == 1){
            printf("1\n");
            continue;
        }
        if(n == 1 && m == 1){
            printf("%lld\n",k);
            continue;
        }
        divide(m);
        divide(n);
        getFac();
        printf("%lld\n",solve());
    }
    return 0;
}

你可能感兴趣的:(组合数学,数论)