poj2773 Happy 2006

题意:求第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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值