素数筛专题精讲

自作多情 提交于 2020-02-23 22:52:18

素数筛

筛法的思想是去除要求范围内所有的合数,剩下的就是素数 了,而任何合数都可以表示为素数的乘积,因此如果已知一 个数为素数,则它的倍数都为合数。
事前需知:
1.sizeof和strlen的区别
strlen计算字符串的长度,以’\0’为字符串结束标志
sizeof是分配的数组实际所占的内存空间大小,不受里面存储内容
2.每种类型的变量都有各自的初始化方法,memset() 函数可以说是初始化内存的“万能函数”,通常为新申请的内存进行初始化工作。它是直接操作内存空间,mem即“内存”(memory)的意思。该函数的原型为:

 #include <string.h>
void *memset(void *s, int c, unsigned long n);

memset() 函数函数的功能是:将指针变量 s 所指向的前 n 字节的内存单元用一个“整数” c 替换,注意 c 是 int 型。s 是 void* 型的指针变量,所以它可以为任何类型的数据进行初始化。
一.复杂度:nlogn

long long su[max],cnt;
bool isprime[max];
void prime()
{
    cnt=1;
    memset(isprime,1,sizeof(isprime));//初始化认为所以数都是素数
    isprime[0]=isprime[1]=0;//0和1不是素数
    for(long long i=2;i<=max;i++)
    {
        if(isprime[i])//保存素数
        {
            su[cnt++]=i;
        }
        for(long long j=i*2;j<=max;j+=i)//素数的倍数都为合数
        {
            isprime[j]=0;
        }
    }
}

二.复杂度:nloglogn(埃shi塞)常用
合数的倍数一定会在筛素数倍数时候被筛掉,所以只筛素数就好

const int N=1e7+1;
int prime [N];
int b[N];
int cnt=0,max1=1e7;
int init()
{
    memset(b,1,sizeof(b));
    b[0]=b[1]=0;
    for(int i=2; i<max1; i++)
    {
        if(b[i])
        {
            prime[++cnt]=i;
            for(int j=2; j*i<=max1; j++)
                b[i*j]=0;
        }
    }
    return 0;
}

三.复杂度0(n)线性筛
素数筛可以优化,普通的线性筛法虽然大大缩短了求素数的时间,但是实际上还是做了许多重复运算,比如2*3=6,在素数2的时候筛选了一遍,在素数为3时又筛选了一遍。如果只筛选小于等于素数i的素数与i的乘积,既不会造成重复筛选,又不会遗漏。时间复杂度几乎是线性的。
我们要筛1~n中的素数,然后先默认他们都是素数,最外层枚举1~n的所有数,如果它是素数,就加到素数表,对于每一个枚举的i,枚举素数表里的数,然后素数就会标记自己i倍的数不是素数,(素数的倍数不是素数)枚举素数表什么时候停?枚举到i的最小质因子,标记完就可以停了,保证每个数只被他的最小质因子筛掉。例如:外层i=15时,素数表里:2,3,5,7,11,132*15=30,把30筛掉;3*15=45,把45筛掉,因为15%3==0,退出里面的循环;15是被3筛掉的,因为3是15的最小素因子。

const int N=1e7+1;
int prime[N];
int b[N];
int cnt=0,max1=1e7;
int init()
{
memset(b,1,sizeof(b));
b[0]=b[1]=0;
for(int i=2;i=max1)
{if(b[i])
prime[cnt++]=i;
 for(int j=1;j<=cnt&&prime[j]*i<=max1;j++)
{
   b[prime[j]*i]=0;
   if(i%prime[j]==0)
   break;
   }
}
return;
}

判断素数

sqrt判别O(√N)
如果x可以表示为两个因子相乘x=a*b
假设a<=b
那么x>=a*a
a<=√x
只需要枚举a<=√x就可以了
int su(LL n)
{
int flag=0;
for(int i=1;prime[i]<=sqrt(n*1.0);i++)
if(n%prime[i]==0)
{flag=1;break;}
if(n==1)flag=1;
return flag;}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!