题意:求第K个与m互素的数
解法一:二分答案。不断计算前K个数与m互素的数的个数(m*logm),通过二分(logINF)可以找到答案。
复杂度:O(log(INF)*m*log(m))
解法二:找出前m个数中与m互素的数(m*logm),并统计个数num。(K/num)*m+prime[K%num]即为答案
复杂度:O(m*logm)
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#define lowbit(x) x&(-x)
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
#define rad 10000
const ll INF = 0x0fffffffffffffff;
const ll maxp = 10000+10;
ll m,K;
bool not_prime[maxp];
vector<ll> prime,factor;
void make_prime(){//找到[1,sqrt(M)]内的所有质数
memset(not_prime,0,sizeof(not_prime));
prime.clear();
not_prime[0]=not_prime[1]=1;
for(ll i=2;i<maxp-5;i++){
if(!not_prime[i]) prime.push_back(i);
for(ll j=0;j<prime.size(),i*prime[j]<maxp-5;j++){
not_prime[i*prime[j]]=1;
if(!(i%prime[j])) break;
}
}
}
void divided(ll x){
factor.clear();
for(ll i=0;i<prime.size();i++){
if(prime[i]*prime[i]>x) break;
if(x%prime[i]==0){
factor.push_back(prime[i]);
while(x%prime[i]==0) x/=prime[i];
}
}
if(x!=1) factor.push_back(x);
}
ll husunum(ll a,ll n){//[1,a]区间内与n互素的数的个数
ll len,tmp,tmpnum,ans;
ans=0;
len=factor.size();
for(ll i=1;i<(1<<len);i++){
tmp=1,tmpnum=0;//初始化位置!
for(ll j=0;(1<<j)<=i;j++){
if((1<<j)&i){
tmp*=factor[j];
if(tmpnum) tmpnum=0;
else tmpnum=1;
}
}
if(tmpnum) ans+=(a/tmp);
else ans-=(a/tmp);
}
return a-ans;
}
int main(){
//freopen("a.txt","r",stdin);
make_prime();
while(scanf("%lld%lld",&m,&K)!=EOF){
ll l=0,r=INF;
divided(m);
while(l<r){
ll mid=(l+r)/2;
ll tmp=husunum(mid,m);
if(tmp>=K) r=mid;
else l=mid+1;
}
printf("%lld\n",l);
}
return 0;
}