质数筛
判断一个数是否为质数的方法
暴力求解
时间复杂度为\(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