数学知识——质数筛

一:判定质数以及分解质因数

1.试除法判定质数O(sqrt(n)):

  质数是除1和本身以外,不能被任何数整除的数。

 

  试除法判定 m 是否为质数的过程:

    1.先特判 m==2 和 1 的情况

    2. for 循环从 i = 2 遍历到 m / i ,如果期间有 i 能整除 m ,则不是质数。如果循环结束了,则证明m是质数。

 

  为什么遍历到m/i,而不是m:

    因为24=2*12,循环到2的时候已经可以判断24不是质数,没必要再循环到12。(节省时间)

  

数学知识——质数筛
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 bool isprimes(int m)
 5 {
 6     if(m==2)return 1;
 7     if(m==1)return 0;
 8     for(int i=2;i<=m/i;i++)
 9     {
10         if(m%i==0)return 0;
11     }
12     return 1;
13 }
14 
15 int main()
16 {
17     int n;
18     cin>>n;
19     for(int i=1;i<=n;i++)
20     {
21         int m;
22         cin>>m;
23         if(isprimes(m))puts("Yes");
24         else puts("No");
25     }
26     
27     
28     return 0;
29 }
试除法判定质数

 

2.六倍筛法O(sqrt(n)/3):

 

数学知识——质数筛
1 bool Is_prime(int n)
2 {
3     if(n==1) return false;
4     if(n==2||n==3) return true;
5     if(n%6!=1&&n%6!=5) return false;
6     for(register int i=5;i*i<=n;i+=6)
7         if(n%i==0||n%(i+2)==0) return false;
8     return true;
9 }
六倍筛法

 

3.试除法分解质因数:

  质因数定义:质因数(素因数或质因子)在数论里是指能整除给定正整数的质数。

  正整数的因数分解可将正整数表示为一连串的质因子相乘( 如8 = 2 * 2 * 2 )

  

  试除法分解质因数过程:

    1.特判m==1的情况

    2.for循环从2到m/i,期间如果有i能整除m,就while循环求出m能整除i的几次方,过程中就是在不断分解m

    3.循环结束后,如果m>1,则单独输出m (比如7)

 

数学知识——质数筛
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 void divide(int m)
 5 {
 6     if(m==1)cout<<m<<" "<<m<<endl;
 7     for(int i=2;i<=m/i;i++)
 8     {
 9         if(m%i==0)
10         {
11             int cnt=0;
12             while(m%i==0)
13             {
14                 cnt++;
15                 m/=i;
16             }
17             if(cnt)cout<<i<<" "<<cnt<<endl;
18         }
19     }
20     if(m>1)cout<<m<<" 1"<<endl;
21     puts("");
22 }
23 
24 int main()
25 {
26     int n;
27     cin>>n;
28     for(int i=1;i<=n;i++)
29     {
30         int m;
31         cin>>m;
32         divide(m);
33     }
34     
35     
36     
37     return 0;
38 }
试除法分解质因数

 

二:各种质数筛

 

1.埃氏质数筛法O(nloglogn):

 核心思想:只枚举质数的倍数

 埃氏质数筛的过程:

    1.特判m==1

    2.for循环从2遍历到m

      如果st [ i ] 为0(说明 i 是质数),cnt++(计数)

      for循环 j 从 i 到小于 m 的值,进制为 i 的乘数,将 j 标记 st [ j ] = 1( i 的倍数都不是质数,直接排除)

数学知识——质数筛
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N=1e6+100;
 5 int primes[N],cnt;
 6 bool st[N];
 7 void get_primes(int m)
 8 {
 9     if(m==1)cnt=0;
10     for(int i=2;i<=m;i++)
11     {
12         if(!st[i])
13         {
14             primes[cnt++]=i;
15             for(int j=i*2;j<=m;j+=i)st[j]=1;
16         }
17 
18     }
19     
20 }
21 
22 int main()
23 {
24     int n;
25     cin>>n;
26     get_primes(n);
27     cout<<cnt<<endl;
28     
29     
30     
31     return 0;
32 }
埃氏筛

 

2.欧拉筛O(n):

  核心思想:让每个合数只被最小质因数筛

  关键点: 

for(int j=0;primes[j]<=m/i;j++)
{
  st[primes[j]*i]=1;
  if(i%primes[j]==0)break;
}

    1.当i%primes [ j ]==0时,证明primes [ j ]是i的最小质因数,那么pj也是i*pj的最小质因数

    2.当i%primes [ j ]!=0时,证明primes [ j ]小于i的最小质因数,但pj仍是i*pj的最小质因数

    根据1和2得:无论pj是否能整除i,pj都是i*pj得最小质因数,而欧拉筛就是利用最小质因数来筛掉合数的,所以当循环到pj时,pj就是pj*i的最小质因数,一定会把pj*i给筛掉

    就是st[primes[j]*i]=1;这一步啦

    3.因为欧拉筛利用的是最小质因数筛掉合数,且for循环是递增的,所以当i能被pj整除说明pj就是i的最小质因数,而p [ j + 1 ]就大于i的最小质因数了,不应该循环到这一步。

    就是if(i%primes[j]==0)break;这一步啦

数学知识——质数筛
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N=1e6+100;
 5 int primes[N],cnt;
 6 bool st[N];
 7 void get_primes(int m)
 8 {
 9     if(m==1)cnt=0;
10     for(int i=2;i<=m;i++)
11     {
12         if(!st[i])primes[cnt++]=i;
13         for(int j=0;primes[j]<=m/i;j++)
14         {
15             st[primes[j]*i]=1;
16             if(i%primes[j]==0)break;
17         }
18 
19     }
20     
21 }
22 
23 int main()
24 {
25     int n;
26     cin>>n;
27     get_primes(n);
28     cout<<cnt<<endl;
29     
30     
31     
32     return 0;
33 }
欧拉筛

 

上一篇:筛质数


下一篇:Android 学习第13课,android 实现发送短信的功能