zoukankan      html  css  js  c++  java
  • [LOJ6235]区间素数个数

    题目大意:
      给定$n(nleq10^{11})$,求$pi(n)$。

    思路:
      计算$pi$函数有$O(n^{frac23})$的Lehmer算法,这里考虑$O(frac{n^{frac34}}{ln n})$的洲阁筛。
      我们可以将答案分为$leqsqrt n$的质数个数和$>sqrt n$的质数个数。
      其中$leqsqrt n$的质数个数可以线性筛预处理,而$>sqrt n$的质数个数相当于用$leqsqrt n$的质数筛这$n$个数后剩下的数的个数。
      若用$f[i][j]$表示$1sim j$中与前$i$个数互质的数的个数,则转移方程为$f[i][j]=f[i-1][j]-f[i-1][lfloorfrac j{p_i} floor]$。$pi(n)simfrac n{ln n}$,$j$有$sqrt n$种取值,时间复杂度$Oleft(frac n{lnsqrt n} ight)=Oleft(frac n{ln n} ight)$。
      当$p_{i+1}>j$时,$f[i][j]=1$。所以当$p_i>frac j{p_i}$时,转移方程变为$f[i][j]=f[i-1][j]-1$。
      因此对于每一个$j$,只需计算$p_i^2leq j$的$f[i][j]$即可。对于$p_i^2>j$的$j$,可以记录最后一步的$i$是多少,转移的时候把那些$1$一起减掉。答案就是一开始线性筛求出的$leqsqrt n$的质数个数+用$leqsqrt n$筛完剩下的数。注意筛完除了那些$>sqrt n$的质数,还会剩下$1$,因此最后要把$1$去掉。
      时间复杂度$Oleft(frac{n^frac34}{ln n} ight)$。

     1 #include<cmath>
     2 #include<cstdio>
     3 #include<cctype>
     4 #include<algorithm>
     5 typedef long long int64;
     6 inline int64 getint() {
     7     register char ch;
     8     while(!isdigit(ch=getchar()));
     9     register int64 x=ch^'0';
    10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    11     return x;
    12 }
    13 const int LIM=316228,P=27294;
    14 bool vis[LIM];
    15 int lim,p[P],sum[LIM],last[LIM*2],cnt;
    16 int64 val[LIM*2],f[LIM*2];
    17 inline void sieve() {
    18     for(register int i=2;i<=lim;i++) {
    19         if(!vis[i]) p[++p[0]]=i;
    20         sum[i]=sum[i-1]+!vis[i];
    21         for(register int j=1;j<=p[0]&&i*p[j]<=lim;j++) {
    22             vis[i*p[j]]=true;
    23             if(i%p[j]==0) break;
    24         }
    25     }
    26 }
    27 int main() {
    28     const int64 n=getint();
    29     lim=sqrt(n);
    30     sieve();
    31     for(register int64 i=1;i<=n;i=n/(n/i)+1) {
    32         val[++cnt]=n/i;
    33     }
    34     std::reverse(&val[1],&val[cnt]+1);
    35     std::copy(&val[1],&val[cnt]+1,&f[1]);
    36     for(register int i=1;i<=p[0];i++) {
    37         for(register int j=cnt;j;j--) {
    38             const int64 k=val[j]/p[i],pos=k<=lim?k:cnt+1-n/k;
    39             if(k<p[i]) break;
    40             f[j]-=f[pos]+last[pos]-i+1;
    41             last[j]=i;
    42         }
    43     }
    44     printf("%lld
    ",sum[lim]+f[cnt]-1);
    45     return 0;
    46 }
  • 相关阅读:
    asp.net控件开发基础(转)
    如何在C#中直接操作C++结构体(转)
    如何打造自己的代码段
    WeifenLuo.WinFormsUI.Docking.dll 源码分析(一)
    软件竞标流程与要点【转】
    C#进制转换
    使用 DpaToolkit 对 C#类库进行反向建模
    算法的时间复杂度(计算实例)
    C#操作SQLServer的Image字段
    不同进制之间的转换
  • 原文地址:https://www.cnblogs.com/skylee03/p/8482432.html
Copyright © 2011-2022 走看看