链接
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.5≈316227之内的素数
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,j−1)−(g(⌊pjn⌋)−(j−1))
复杂度
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;
}