质数筛

判断一个数是否为质数的方法

暴力求解

时间复杂度为\(O(sqrt(n))\)
适用于单次查询

bool isprime(long long x){//暴力做法
	if(x==1) return false;
	for(long long i=2;i*i<=x;++i){
		if(x%i==0) return false;
	}
	return true;
}

埃筛

快捷判断1~N之间的数是不是质数
基于质数的倍数是合数的概念,我们从而开始遍历值域\([1,N]\),每找到一个质数,就将其开始的所有的倍数都打上标记,以此类推即可,预处理后比暴力稍快
适用于不太大值域?,多次查询
代码:
\(i:1\)~\(maxm\)
\(j:i\times i\)~\(maxm\)

const int maxm=5e6+5;
bool isprime[maxm];//数组标记快
void pre(){
	isprime[1]=1;//为1不是质数
	for(long long i=2;i<=maxm;++i){
		if(isprime[i]==0){
			for(long long j=i*i;j<=maxm;j+=i){
				isprime[j]=1;
			}
		}
	}
}

欧拉筛

在埃筛的过程中存在重复的情况,例如30会被3和5筛两遍,所以这就是埃筛中存在的赘余判断。
代码:

int N = 1e6 + 5, cnt = 0;
vector<bool> isprime(N, true);//判断素数
vector<long long> prime;//存储素数
void pre(){
	long long t;
	isprime[1] = false;
	for(long long i = 2; i < N; ++ i){
		if(isprime[i]){
			prime.push_back(i);
			++ cnt;
		}
		for(int j = 0; j < cnt; ++ j){
			t = i * prime[j];
			if(t > N) break;
			isprime[t] = false;
			if(i % prime[j] == 0) break;
		}
	}
	return ;
}

米勒-拉宾素性检验(MillerRabbin)

#include<iostream>
#define ll long long
#define lll __int128

using namespace std;

lll qmksm(ll a,ll b,ll m){
	lll s=1,z=a%m;
	while(b>0){
		if(b&1==1){
			s*=z;
			s%=m;
		}
		z*=z;
		z%=m;
		b>>=1;
	}
	return s;
}

bool prime(ll n){
	if(n<3) return n==2;
	if(n%2==0) return 0;
	ll i,j,d=n-1,r=0,tss[8]={-1,2,325,9375,28178,450775,9780504,1795265022};
	while(d%2==0) d/=2,r++;
	for(i=1;i<=7;i++){
		lll zc=qmksm(tss[i],d,n);
		if(zc<=1 or zc==n-1) continue;
		for(j=0;j<=r-1;j++){
			zc=(zc%n*zc%n)%n;
			if(zc==n-1 and j!=r-1){
				zc=1;
				break;
			}
			if(zc==1) return 0;
		}
		if(zc!=1) return 0;
	}
	return 1;
}

int main(){
	ll n;
	while(scanf("%lld",&n)!=EOF){
		if(prime(n)) printf("Y\n");
		else printf("N\n");
	}
	return 0;
}

相关资料

https://blog.csdn.net/holly_Z_P_F/article/details/85063174
https://oi-wiki.org/math/number-theory/sieve/


例题

1e18范围判质数 https://loj.ac/p/143

欧拉筛判第k大素数 https://www.luogu.com.cn/problem/P3383

posted on 2023-04-03 11:28  Qiansui  阅读(28)  评论(0编辑  收藏  举报