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 <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+10;
ll fac[maxn],len;
set<ll> 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<<len); i++){
ll tmp = 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;
}