求小于n的素数个数()
程序员文章站
2022-03-13 10:06:24
...
求小于n的素数个数()
//O(n^3/4)
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define rop(i,a,b) for(int i=(a);i<(b);i++)
using namespace std;
typedef long long ll;
const int maxn=4e5+10;
ll phi[maxn/10][105], prime[maxn], pre[maxn];
int x;
bool vis[maxn];
unordered_map<ll,ll>mp;
void init(){
rop(i,2,maxn)
{
if(!vis[i]) {
prime[x++] = i;
for (int j = 2; j * i < maxn; j++) {
vis[i * j] = true;
}
pre[i]=pre[i-1]+1;
continue;
}
pre[i]=pre[i-1];
}
rep(i,0,maxn/10-5){
phi[i][0] = (ll)i;
rep(j,1,100){
phi[i][j] = phi[i][j-1] - phi[i/prime[j-1]][j-1];
}
}
}
ll mpphi(ll m, ll n){
if(n==0) return m;
if(prime[n - 1] >= m) return 1;
if(m<=maxn/10-5 && n<=100) return phi[m][n];
return mpphi(m, n-1) - mpphi(m/prime[n-1], n-1);
}
ll get_ans(ll x){
if(x < (ll)maxn) return pre[x];
if(mp.count(x))
return mp[x];
ll y = (int)cbrt(x*1.0);
ll n = pre[y];
ll ans = mpphi(x, n) + n -1;
for(ll i=n; prime[i]*prime[i]<=x; i++) ans = ans - get_ans(x/prime[i])+get_ans(prime[i])-1;
return mp[x]=ans;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
init();
ll n;
cin>>n;
ll anss = get_ans(n);
cout<<anss<<endl;
return 0;
}
//O(n^2/3)
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define rop(i,a,b) for(int i=(a);i<(b);i++)
using namespace std;
typedef long long ll;
const int maxn = 5e6+10;
bool vis[maxn];
int prime[maxn], pi[maxn];
int x;
void oulasai(int n)
{
rep (i,2,n)
{
if(!vis[i]) prime[x++]=i;
rop (j,0,x)
{
if(i*prime[j]>n) break;
vis[i*prime[j]]=true;
if(i%prime[j]==0) break;
}
}
}
const int M = 7;
const int PM = 2 * 3 * 5 * 7 * 11 * 13 * 17;
int phi[PM + 1][M + 1], sz[M + 1];
void init(){
oulasai (maxn);
sz[0] = 1;
rep (i,0,PM) phi[i][0] = i;
rep (i,1,M){
sz[i] = prime[i] * sz[i - 1];
rep (j,1,M) phi[j][i] = phi[j][i - 1] - phi[j / prime[i]][i - 1];
}
}
int sqrt2(ll x)
{
ll r = (ll)sqrt(x - 0.1);
while(r * r <= x) ++r;
return int(r - 1);
}
int sqrt3(ll x)
{
ll r = (ll)cbrt(x - 0.1);
while(r * r * r <= x) ++r;
return int(r - 1);
}
ll getphi(ll x, int s)
{
if(s == 0) return x;
if(s <= M) return phi[x % sz[s]][s] + (x / sz[s]) * phi[sz[s]][s];
if(x <= prime[s]*prime[s]) return pi[x] - s + 1;
if(x <= prime[s]*prime[s]*prime[s] && x < maxn)
{
int s2x = pi[sqrt2(x)];
ll ans = pi[x] - (s2x + s - 2) * (s2x - s + 1) / 2;
rep (i,s+1,s2x) ans += pi[x / prime[i]];
return ans;
}
return getphi(x, s - 1) - getphi(x / prime[s], s - 1);
}
ll getpi(ll x)
{
if(x < maxn) return pi[x];
ll ans = getphi(x, pi[sqrt3(x)]) + pi[sqrt3(x)] - 1;
for(int i = pi[sqrt3(x)] + 1, ed = pi[sqrt2(x)]; i <= ed; ++i) ans -= getpi(x / prime[i]) - i + 1;
return ans;
}
ll lehmer_pi(ll x)
{
if(x < maxn) return pi[x];
int a = (int)lehmer_pi(sqrt2(sqrt2(x)));
int b = (int)lehmer_pi(sqrt2(x));
int c = (int)lehmer_pi(sqrt3(x));
ll sum = getphi(x, a) +(ll)(b + a - 2) * (b - a + 1) / 2;
for (int i = a + 1; i <= b; i++)
{
ll w = x / prime[i];
sum -= lehmer_pi(w);
if (i > c) continue;
ll lim = lehmer_pi(sqrt2(w));
for (int j = i; j <= lim; j++) sum -= lehmer_pi(w / prime[j]) - (j - 1);
}
return sum;
}
int main(){
init();
ll n;
while(~scanf("%lld",&n)){
printf("%lld\n",lehmer_pi(n));
}
return 0;
}
上一篇: 深入浅析PHP中的建造者模式
下一篇: 关于面向对象的一些想法