小奇学数论(loj 6235 区间素数个数)题解

min_25筛

昨天就想切这道题,结果晚上在划水,今天上午在考试,鸽到下午才做出来

本题做法有洲阁筛,min_25筛,某黑科技的素数筛等

注意到题目并未让我们输出具体有多少素数,所以可以用min_25筛

min_25筛的讲解在这里,自己看吧(捂脸

这里就借用这篇博客中的定义,谈此题的解法

设p为质数,区间质数个数为pl

定义f(p)=1,f(p*k)=0

求g(pl,n)

我们构造f'(i)=1,则函数f'满足:

  1. f'在质数处的取值与 f 相同。
  2. f′是完全积性函数。
  3. f'可以快速求前缀和。

故g的初值为

\(g(0,n)=n-1\)

g的递推式为

\(g(j,n)=\begin{cases}g(j-1,n)&p_j^2>n\\g(j-1,n)-(g(j,\lfloor\dfrac{n}{p_j}\rfloor)-(j-1))&p_j^2\le n\end{cases}\)

直接算即可。时间复杂度 \(O(\frac{N^{3/4}}{\log N})\)

是时候给出此题的最短(最快?)代码了!

我,WXL,永不打表!!!

#include<bits/stdc++.h>
using namespace std;

#define go(i,a,b) for(int i=a;i<=b;++i)
#define fo(i,a) for(int i=0;i<a;++i)
#define int long long
#define id(x) ((x)<=sq?id1[x]:id2[n/(x)])

const int N=330000;
typedef int aray[N];

int n,pl,tot,sq;
aray p,g,val,id1,id2;
bool vis[N];

void init(){
    sq=sqrt(n);
    go(i,2,sq){
        if(!vis[i]) p[pl++]=i;
        for(int *j=p;j<p+pl&&(*j)*i<=sq;++j){
            vis[(*j)*i]=1;
            if(i%(*j)==0) break;
        }
    }
    for(int i=1,j;i<=n;i=j+1){
        j=n/(n/i);
        val[++tot]=n/i;
        n/i<=sq?id1[n/i]=tot:id2[j]=tot;
        g[tot]=val[tot]-1;
    }
}

signed main(){
    //freopen("input.txt","r",stdin);
    cin>>n;
    init();
    fo(i,pl)
        go(j,1,tot){
            if(p[i]*p[i]>val[j]) break;
            g[j]-=g[id(val[j]/p[i])]-i;
        }
    printf("%lld",g[1]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/White-star/p/11743827.html