zoukankan      html  css  js  c++  java
  • 质数筛

    本文将介绍两周质数筛算法,分别是埃拉托斯特尼筛法(简称埃氏筛)与欧拉筛。

    埃氏筛
    基本思想:任意整数x的倍数2x,3x ···都不是质数,可以除去
    算法基本流程:从2开始,从小到大扫描每个数字x,将它的倍数2x,3x ···,(lfloor N/x floor *x)如果没标记的就打上合数标记
    ,当扫描到x时,若x未被标记,则说明x不能被2~x-1的数整除,所以x是质数。
    引用https://www.cnblogs.com/orion7/p/7491484.html的一张图片

    另外,我们可以发现,有些数字会被重复标记,比如6会被2和3标记。浪费了时间。
    实际上,小于(x^2)的x的倍数在扫描到x之前就已经被标记了。因此,我们可以加个小优化,让x的倍数从(x^2)开始枚举。(虽然是小优化,但是在洛谷却是100pts和40pts的差距)

    inline void Eratosthenes1(int n) {
    	for(int i = 2; i<= n; i++) {
    		if(vis[i]) continue;
    			prime[++cnt] = i ;
    			for(int j = i;1ll* i * j <=1ll* n; j++)
    				vis[i * j] = true;
    	}
    }
    
    

    时间复杂度$$O(sum_{质数p le N} frac{N}{p} ) =O(N loglog N)$$
    证明见https://zhuanlan.zhihu.com/p/272483362(太弱了,不会证明,以后一定补上):

    欧拉筛(线性筛)
    即使埃氏筛优化了,也还是会重复标记一些数字,比如12被2,3重复标记了,原因在于我们没有确定12的唯一产生方式。
    根据算术基本定理,每个大于1的自然数都有唯一的有限个素数乘积表示,所以我们在生成一个需要被标记的合数时,只要在现有的数乘上一个质因子,并且让这个质因子是这个合数的最小质因子。采用该法,每个合数只会被它的最小质因数筛一次。

    inline void EulerSieve(int n) {
    	for(int i(2); i <= n; ++i) {
          if(!v[i])//v[i]记录i的最小质因子 
          {
          	v[i]=i;//如果i是质数,那么它只有两个因子,1和它本身,所以它的最小质因子为i 
          	prime[++cnt]=i;
    	  }
          for(int j=1;j<=cnt;++j){
          	if(prime[j]>v[i]||prime[j]>n/i) break;
    		  //i有比prime[j]更小的质因子或者i乘prime[j]会超出范围了 
    		 v[prime[j]*i]=prime[j]; 
    	  }
    	}
    }
    

    本文来自博客园,作者:{2519},转载请注明原文链接:https://www.cnblogs.com/QQ2519/p/15046801.html

  • 相关阅读:
    泛型程序设计详解(一)
    面向对象三大特性-----封装、继承、多态
    委托与事件-委托事件案例(三)
    委托与事件-事件详解(二)
    委托与事件-委托详解(一)
    抽象类及接口详解
    基础类型详解下
    C#类型详解
    【JVM】-- JVM内存结构
    【redis】-- redis的持久化(作为数据库)
  • 原文地址:https://www.cnblogs.com/QQ2519/p/15046801.html
Copyright © 2011-2022 走看看