hdu5901 Count primes

链接

http://acm.hdu.edu.cn/showproblem.php?pid=5901

题解

参考埃氏筛素数法
g ( n , j ) g(n,j) g(n,j)表示用前 j j j个素数筛完之后还剩下多少数
由于一个数 n n n的最小质因数肯定不超过 n \sqrt n n ,所以这道题我只需要用到 1 0 5.5 ≈ 316227 10^{5.5}\approx 316227 105.5316227之内的素数
g ( n , j ) = g ( n , j − 1 ) − ( g ( ⌊ n p j ⌋ ) − ( j − 1 ) ) g(n,j) = g(n,j-1) - ( g(\lfloor \frac{n}{p_j} \rfloor) - (j-1) ) g(n,j)=g(n,j1)(g(pjn)(j1))
复杂度 O ( n 1 − ϵ ) O(n^{1-\epsilon}) O(n1ϵ),实测 1.5 s 1.5s 1.5s

代码

#include <bits/stdc++.h>
#define maxn 1000010
using namespace std;
typedef long long ll;
struct EasyMath
{
    ll prime[maxn];
    bool mark[maxn];
    void get_prime(ll N)
    {
        ll i, j;
        for(i=2;i<=N;i++)mark[i]=false;
        *prime=0;
        for(i=2;i<=N;i++)
        {
            if(!mark[i])prime[++*prime]=i;
            for(j=1;j<=*prime and i*prime[j]<=N;j++)
            {
                mark[i*prime[j]]=true;
                if(i%prime[j]==0)break;
            }
        }
    }
}em;
struct min_25   //f(p^k)=p^k * (p^k - 1)
{
    ll n, g[maxn], id1[maxn], id2[maxn], lis[maxn], _m;
    inline ll getid(ll x)
    {
        return x<=_m ? id1[x] : id2[n/x];
    }
    void calcg()
    {
        ll i, j;
        //初始化g
        for(i=1;i<=n;i=j+1)
        {
            j=n/(n/i);
            lis[++*lis]=n/i;
            if(n/i<=_m)id1[n/i]=*lis;
            else id2[n/(n/i)]=*lis;
            ll t=n/i;
            g[*lis] = t-1;
        }
        //求g
        for(j=1;j<=*em.prime;j++)
        {
            auto p=em.prime[j];
            for(ll k=1;k<=*lis;k++)
            {
                if(p*p>lis[k])break;
                ll t = getid(lis[k]/p);
                g[k]-=g[t]-(j-1);
            }
        }
    }
    ll run(ll N)
    {
        _m=sqrt(N);
        *lis=0;
        n=N;
        calcg();
        return g[getid(n)];
    }
}m25;
int main()
{
    ios::sync_with_stdio(false);
    em.get_prime(400000);
    ll n;
    while(cin>>n)
    {
        cout<<m25.run(n)<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值