素数筛
筛法的思想是去除要求范围内所有的合数,剩下的就是素数 了,而任何合数都可以表示为素数的乘积,因此如果已知一 个数为素数,则它的倍数都为合数。
事前需知:
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;}
来源:CSDN
作者:上帝全栈
链接:https://blog.csdn.net/qq_45899321/article/details/104406844