筛素数,判素数,1E11以内素数个数
筛素数
埃式筛法O(nlog(log(n)) )
const int N = 1e7+2;
bool notPrime[N];
int sushu[700000],cnt;
void Ero_getPrime() {
//埃式筛法
int n = N-1;
cnt = 0;
for(int i=2;i<=n;++i) {
if(!notPrime[i]) {
sushu[cnt++] = i;
if(i<=n/i)
for(int j=i*i;j<=n;j+=i) //i*i之前的合数都被更小的质因数筛过了
notPrime[j] = true;
}
}
}
2筛掉了4, 6, 8, 10, 12,14,16,18,20,22,24,26,28,30,32…
3筛掉了9,12,15,18,21,24,27,30,33…
5筛掉了25,30,35,50,45…
我们发现:30 = 2*15 = 3*10 = 5*6, 被筛了不止一次。
j从i*i开始,是因为i*i之前的合数,一定被它最小的质因子筛过了(可能也被更大的质因子筛过)
欧拉筛(线性筛)。每个合数被其最小的质因子筛掉,只筛一次,接近O(n)
const int N = 1e7+2;
bool notPrime[N];
int sushu[700000],cnt;
void getPrime() {
cnt = 0;
int n = N-1;
for(int i=2;i<=n;++i) {
if(!notPrime[i]) sushu[cnt++] = i;
for(int j=0;j<cnt&&1ll*i*sushu[j]<=n;++j) {
notPrime[i*sushu[j]] = true;
if(i%sushu[j]==0) break;
}
}
}
判素数
- 从2到sqrt(n)试除
bool solve(long long x) {
if(x<2) return false;
for(int i=2;i<=x/i;++i) {
if(x%i==0) {
return false;
}
}
return true;
}
- 大于3的素数都满足x = 6N-1 或 x = 6N+1的性质。
我们在试除的时候用质数试除当然是更快的[N以内的素数个数大约为:N/ln(N)], 我们可以直接用6i-1和6i+1来搜,这样的复杂度就变成了O(sqrt(N)/6)
bool isPrime(long long x) {
//快速判素数
if(x<2) return false;
if(x==2||x==3) return true;
if(x%6!=5&&x%6!=1) return false;
for(int j=5;j<=x/j;j+=6) {
if(x%j==0) return false;
if(x%(j+2)==0) return false;
}
return true;
}
- 费马素性检验(非确定性的)
由费马小定理:如果P是素数,且a不是P的倍数, 那么a^(P-1)%P = 1 ------(1)
随机找k个(k为参数)a1,a2,… ak, 带入1式,只要有一个不满足,那么就说明P不是素数。
如果都满足,那么有一定的概率可以认为是素数。但是存在迈克卡尔数。
不一定检测得出来
long long fast_sum(long long a,long long b,long long mod) {
if(!a||!b) return 0;
long long ans = 0;
while(b>0) {
if(b&1) ans = (ans+a)%mod;
a = (a<<1)%mod;
}
return ans;
}
long long fast_pow(long long a,long long b,long long mod)
{
if(a==0) return 0;
long long ans = 1;
while(b>0) {
if(b&1) {
ans = fast_sum(ans,a,mod);
}
a = fast_sum(a,a,mod);
b>>=1;
}
return ans;
}
bool Fermat(long long x) {
//费马小定理:若P为素数,则a^(P-1) % P = 1 非确定性的!
if(x<2) return false;
if(x==2||x==3) return true;
int num = min(x-2,20ll);
for(int i=0;i<num;++i) {
long long a = 1ll*rand()*rand