素数问题
素数(质数):除了1和它本身没有其他的因子;
合数:反之
原理:
1.算术基本定理:任何一个大于1的自然数 N,那么N可以唯一分解成有限个质数的乘积。
2. 若一个数可以进行因数分解,则得到的两个数一定是有一个>=sqrt(x),另一个<=sqrt(x)。
3.1-N内的素数的个数大约是logN。
素数主要有两个基本问题:
1.求1—n中的所有素数
2.判断一个数是否是素数
暴力写法:
#include<bits/stdc++>
#define MAXN 1e5;
bool isprime[MAXN];
bool is_prime(int x)
{
int flag=0;
for(int i=2;i<sqrt(x);i++)
{
if(x%i==0)
{
flag++;
break;
}
}
if(flag)
{
isprime[x]=false;
return false;
}
else
{
isprime[x]=true;
return true;
}
}
int init(int N)
{
int cnt=0; //记录素数的个数
for(int i=2;i<=N;i++)
{
if(is_prime(i))
cnt++;
}
return cnt;
}
埃氏筛
埃拉托斯特尼筛法,利用当前已经找到的素数,从后面的数中筛去当前素数的倍数。
原理:每个大于1的正整数n都可以表示成素数之积的形式。所以在1到n中一个数若不是素数,一定会被筛到。
复杂度:O(n*lglgn),近似为O(n)。
缺点:某些数被每个质因子都筛了一遍导致速度减慢。
#define MAXN 1e5
bool isnotprime[MAXN];
int prime[MAXN];
int ant=0;
void init(int N) //求1到N中所有的素数
{
memset(prime, 0, sizeof(prime));
for(int i =2;i<m;i++)
{
if (!isnotprime[i])
{
prime[ant++]=i;// prime[0]=2
for (int k= i*i; k<=N; k+=i)
isnotprime[k] = 1;
}
}
欧拉筛
和埃氏筛法的区别是对于每一个要筛除的数,欧拉筛法只筛除一次。
复杂度:O(n)
#include<bits/stdc++.h>
using namespace std;
const int MAXN=100000+5;
bool isprime[MAXN];//isprime[]表示i是不是质数
int prime[MAXN], tot;//prime[]用来存质数
void init(int N)
{
memset(isprime,true,sizeof(isprime)/sizeof(bool)*N); //初始化所有的数为质数
for(int i=2;i<=N;i++)
{
if(isprime[i])
prime[tot ++] = i;//把质数存起来
for(int j=0;j<tot&&i*prime[j]<=N;j++)
{
isprime[i*prime[j]]=false;
if(i%prime[j]==0) break;//保证每个合数被它最小的质因数筛去
}
}
}
埃筛和欧拉筛复杂度其实相差不是很多,更推荐埃筛,毕竟好写很多。