数论_埃氏筛法(求区间内多少素数)

埃拉托斯特尼(公元前276—公元前194)

埃拉托斯特尼是古希腊著名的数学家、地理学家、天文学家。他先在亚历山大港学习,后又转至雅典。公元前236年,托勒密三世指定他为亚历山大图书馆的图书管理员和馆长。他跟阿基米德是好朋友。埃拉托斯特尼的主要贡献包括:

埃拉托斯特尼筛法:寻找素数的方法。

地理常数测量:日地间距的测量(现在称一个这样的距离为一个天文单位)、地月间距的测量、测量赤道与黄道之间的偏角、地球半径测量等。

精确地图绘制:当时只有托勒密等级的人物能绘出同等级的地图。

算法数学原理:
埃拉托斯特尼筛法是快速筛选素数的算法,在处理大量整数是否是素数时有较高的效率。

例:筛选小于n的整数并记录结果。

解:计算sqrt(n),∵对于任意的z<n,若z为合数,不妨设z=a*b,则必有min(a,b)<sqrt(n)

∴所有小于n的合数均可被小于sqrt(n)的整数整除

从2开始,依次去除小于n的整数中能被其整除的数,最后剩下的就是素数

int prime[maxn];
bool is_prime[maxn];//is_prime[i]是true表示i是素数
//返回n以内素数的个数
int sieve(int n)
{
    int p=0;
    for(int i=0;i<=n;i++) is_prime[i]=true;
    is_prime[0]=is_prime[1]=false;
    for(int i=2;i<=n;i++){
        if(is_prime[i]){
            prime[p++]=i;
            for(int j=2*i;j<=n;j+=i) is_prime[j]=false;
        }
    }
    return p;
}

  例题:洛谷 P1865  ,

codevs3223 素数密度

[a,b]的素数,只需要

[2,b√]
的素数表即可。这样我们可以筛出这些素数,然后用这些素数筛[a,b]。

注意,j=max(2ll,(l+i-1)/i)*i的意思:

(l+i-1)/i表示大于等于a的i的倍数的最小值。
2则是普遍的i的倍数的最小值,一定不能小于2。
再乘i,j就可以枚举[a,b]之间的合数了。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int SIZE=1000010;
bool vis[SIZE];
bool pri[SIZE];
typedef long long LL;
int main()
{
    LL l,r;
    scanf("%lld%lld",&l,&r);

    for(LL i=2;i<=sqrt(r);i++)
    {
        if(!vis[i])
        {
            for(LL j=i*i;j<=sqrt(r);j+=i) vis[j]=1;

            for(LL j=max(2ll,(l+i-1)/i)*i;j<=r;j+=i) pri[j-l]=1;
        }
    }
    int ans=0;
    for(int i=0;i<=r-l;i++) if(!pri[i]) ans++;
    printf("%d",ans);

    return 0;
}

  

原文地址:https://www.cnblogs.com/passion-sky/p/10087034.html

时间: 2024-10-11 06:36:32

数论_埃氏筛法(求区间内多少素数)的相关文章

素数的计算-埃氏筛法(区间素数利器)

素数,各种素数,各种题总是遇到素数. 下面我们来说一下求素数的一种比较有效的算法. 就是筛法.因为这个要求得1-n区间的素数只需要O(nloglogn)的时间复杂度. 下面来说一下它的思路. 思路:现在又1-n的数字,素数嘛就是除了1和本身之外没有其他的约数,所以有约数的都不是素数. 我们从2开始往后遍历,是2的倍数的都不是素数,所以我们把他们划掉 然后现在从2往后就是3了 因为3的前面没有能整除3的,所以3是素数,然后3的倍数全都不是素数,我们接着划掉. 然后就是5了,因为4是2的倍数不是素数

埃氏筛法(快速筛选n以内素数的个数)

给你一个数n,请问n以内有多少个素数?(n <= 10e7) 一般来说,要是对一个整数进行素数判断,首先想到的是写个函数判断是否为素数,然后调用这个函数,时间复杂度为O(n^(½)),但是要求n以内的素数就略显吃力了. 要是求n以内的素数个数的话,可以用埃式筛选.预处理一下. 先看下面的代码: 1 /* 2 |埃式筛法| 3 |快速筛选素数| |15-7-26| 4 */ 5 #include <iostream> 6 #include <cstdio> 7 using na

埃氏筛法的一般写法

问题: 求[L, R]之间的素数表 解法: 先用埃氏筛法求出[1...sqrt(R)]上的素数表 再在[L, R]上用埃氏筛法求素数 const int N(1e5); bool isprime[N]; int prime[N]; void init(){ memset(isprime, -1, sizeof(isprime)); isprime[0]=isprime[1]=0; int np=0; for(int i=0; i<N; i++){ if(isprime[i]){ prime[np

埃氏筛法(素数筛)

埃式筛法:给定一个正整数n(n<=10^6),问n以内有多少个素数? 做法:做法其实很简单,首先将2到n范围内的整数写下来,其中2是最小的素数.将表中所有的2的倍数划去,表中剩下的最小的数字就是3,他不能被更小的数整除,所以3是素数.再将表中所有的3的倍数划去……以此类推,如果表中剩余的最小的数是m,那么m就是素数.然后将表中所有m的倍数划去,像这样反复操作,就能依次枚举n以内的素数,这样的时间复杂度是O(nloglogn). 题解:如果要是按照一个一个判断是否是素数然后把ans+1,时间复杂度

埃氏筛法&amp;欧拉筛法

埃氏筛法 /* |埃式筛法| |快速筛选素数| |15-7-26| */ #include <iostream> #include <cstdio> using namespace std; const int SIZE = 1e7; int prime[SIZE]; // 第i个素数 bool is_prime[SIZE]; //true表示i是素数 int slove(int n) { int p = 0; for(int i = 0; i <= n; i++) is_p

素数的快速筛选(埃氏筛法)

要枚举n以内的素数,可以用埃氏筛法.这是一个与辗转相除法一样古老的算法. 首先,将2到n范围内的所有整数写下来.其中最小的数字2是素数.将表中所有2的倍数都划去.表中剩余的最小数字是3,它不能被更小的数整除,所以是素数.再将表中所有3的倍数全都划去.依次类推,如果表中剩余的最小数字是m时,m就是素数.然后将表中所有m的倍数全部划去.像这样反复操作,就能依次枚举n以内的素数. int prime[maxn];//第i个素数 bool is_prime[maxn];//is_prime[i]为tru

埃氏筛法之素数

原理: 首先将2~n个数记录下来,2作为最小素数,所以2的倍数不是素数,从记录中划去,扫一遍之后,将3作为最小素数,3的倍数划去,如此下去,求出所有素数.如表格所示: 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2 3 - 5 - 7 - 9 - 11 - 13 - 15 - 17 - 19 - 2 3 - 5 - 7 - - - 11 - 13 - - - 17 - 19 - 代码: 判断是否是素数: bool is_prime(int n

HDU4622:Reincarnation(后缀数组,求区间内不同子串的个数)

Problem Description Now you are back,and have a task to do: Given you a string s consist of lower-case English letters only,denote f(s) as the number of distinct sub-string of s. And you have some query,each time you should calculate f(s[l...r]), s[l

分拆素数和 埃氏筛法

分拆素数和 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 2098 Description 把一个偶数拆成两个不同素数的和,有几种拆法呢? Input 输入包含一些正的偶数,其值不会超过10000,个数不会超过500,若遇0,则结束. Output 对应每个偶数,输出其拆成不同素数的个数,每个结果占一行. Sample Input 30