zoukankan      html  css  js  c++  java
  • 线性筛

    前言

    线性筛是筛素数一种比较常用的方法(实际上,它的用途含有很多,如筛(mu,phi)等玄学的函数)。它的时间复杂度近似于(O(n))

    代码(代码后面有解析)

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    map<int,int> Is_Prime;//保存每一个数是否为质数
    vector<int> Prime;//保存全部质数
    int main()
    {
    	scanf("%d",&n);//筛选2~n内的质数
    	for(int i=2;i<=n;i++) Is_Prime[i]=1;//先默认全部都是质数
    	for(int i=2;i<=n;i++)
    	{
    		if(Is_Prime[i]) Prime.push_back(i);//如果这个数是质数,就将其保存下来
    		for(int j=0;j<Prime.size();j++)//将这个数与已有的质数进行操作
    		{
    			Is_Prime[i*Prime[j]]=0;//将这个数与该质数的积标记为非质数
    			if(!(i%Prime[j])) break;//如果当前数是该质数的倍数,就退出循环(这个在后面会进行解释)
    		}
    	}
    	printf("%d
    ",Prime.size());
    	for(int i=0;i<Prime.size();i++) printf("%d ",Prime[i]);
    	return 0;
    }
    

    解释

    对于(2sim n)之间的一个整数(i),有两种可能性:

    一:它是质数。则此时(Prime[j])必为(i)(一个质数只能被(1)和本身整除,而(Prime[j])不可能为(1),故(Prime[j])(i)),而(i)是刚保存下来的,必然在最末尾,即i后面没有其他可操作的数了,于是退出循环

    二:它是合数。则可得(i=Prime[j]*x)(x)(2sim i)之间的一个整数),此时又有两种可能性:

    1:(x)是质数。则(xge Prime[j])(若(x<Prime[j]),则在对(Prime[j])进行操作前就会对(x)进行操作并退出循环),那么(i)(Prime[j])之后的任意一个数(t)的积(i*t)都可以表示为(Prime[j]*x*t),而(x*t)是一个合数,所以在轮到对(x*t)(Prime[j])进行操作时时就可以得到(i*t),故不需要继续操作了,可以退出循环

    2:(x)是合数。则(x)可以分解为(a*b)的形式(其中(a)是所能取值的数中的最小质数),那么(i=a*b*Prime[j])。对于(a)(Prime[j])的大小关系,又有两种可能性:

    ​ ①:(a<Prime[j])。显然不可能(否则在对(Prime[j])进行操作前就会对a进行操作并退出循环)

    ​ ②:(age Prime[j])(∵age Prime[j],∴b*Prime[j]le x),那么(i)应在对(x)进行操作就已经在对(b*Prime[j])进行操作的时候的时候被判定为非质数,自然无需再判一遍。

  • 相关阅读:
    bzoj 1503
    bzoj 1193 贪心+bfs
    bzoj 1798 线段树
    Codeforces 804D Expected diameter of a tree
    bzoj 1208
    bzoj 3224
    HDU 5115 区间dp
    hihocoder #1162 矩阵加速dp
    分块入门
    bzoj 1036 树链剖分
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/LineSieve.html
Copyright © 2011-2022 走看看