51nod 1184 第N个质数

11 篇文章 0 订阅
3 篇文章 0 订阅

这题正解不用二分的呀…我弱只会二分的
(除了正解,好像有个更厉害的论文解法,然而根本看不懂论文…)

二分+洲阁筛

二分后,问题转化为判定性问题,即1~n有多少个质数
设g[i][j]表示1~j,与前i个质数互质的数的个数,得
g[i][j]=g[i1][j]g[i1][j/prime[i]]
因为二分有多个n,不能递推需要记忆化搜索
只是这样搜肯定T,考虑一些剪枝
j<=p[i] 时,易得 g[i][j]=1
j<p[i]p[i] 时,即与 1j  的质数互质,那么 g[i][j] 就是 1 jj 的质数个数,在预处理了 1j 的质数个数时可以 O(1) 求得

这题二分的东西是单调不降的,要找最小的(显然?)

然后就可以做了(并不是),我一直T某几个点…于是….我优化了一下二分,判了一下数据范围减少二分次数(其实就是打表?)

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn = 11000100;

ll n;
bool v[maxn];
int g[maxn];
int p[maxn],pri;
void pre()
{
    g[1]=0;
    for(int i=2;i<maxn;i++)
    {
        if(!v[i]) p[++pri]=i;
        for(int j=1;j<=pri;j++)
        {
            int k=i*p[j];
            if(k>=maxn) break;
            v[k]=true;
            if(i%p[j]==0) break;
        }
        g[i]=g[i-1];
        if(!v[i]) g[i]++;
    }

}
ll G(const int i,ll j)
{
    if(!i) return j;
    if(i==1) return j-(j>>1);
    if(j<maxn)
    {
        if(j<=p[i]) return 1ll;
        if(j<p[i]*p[i]) return g[j]-i+1;
    }
    return G(i-1,j)-G(i-1,j/p[i]);
}
ll cal(ll x)
{
    if(x<maxn) return g[x];
    ll d=floor(sqrt(x));
    return g[d]+G(g[d],x)-1;
}

int main()
{
    pre();
    scanf("%lld",&n);

    ll l=1,r=22801763489,ans;
    if(n>=900000000) l=20422213579;
    if(n>=950000000) l=21610588367; else r=21610588367;
    if(n>=970000000) l=22086742277; else r=22086742277;
    if(n>=985000000) l=22444149523; else r=22444149523;
    while(l<=r)
    {
        ll mid=(l+r)>>1;
        ll tmp=cal(mid);
        if(tmp>=n) r=mid-1;
        else l=mid+1;
    }
    printf("%lld\n",r+1);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值