Screening of prime numbers (herlike sieve and Euler's sieve) and Euler's Sieve
There are many screening methods for prime numbers
Three common methods are provided here.
All the code given below has passed the test here
Heratosney screening method
Long Name: joy: but the code is short.
The idea is very simple. For every prime number, to enumerate its multiples, its multiples must not be prime numbers.
This ensures that each prime number is screened out.
In addition, we can enumerate $ \ sqrt (n) $ in the first layer, because if the number of the current enumeration is greater than n, the number it can screen must have been enumerated before.
For example:
$/Sqrt (100) = 10 $
It is not difficult to find that the number of screens we have screened from the $20 $ enumeration must have been screened by $5 $.
1 # include <cstdio> 2 # include <cmath> 3 using namespace std; 4 const int MAXN = 10000001; 5 inline int read () 6 {7 char c = getchar (); int f = 1, x = 0; 8 while (c <'0' | c> '9') {if (c = '-') f =-1; c = getchar ();} 9 while (c> = '0' & c <= '9') x = x * 10 + c-48, c = getchar (); return x * f; 10} 11 int vis [MAXN]; 12 int n, m; 13 int main () 14 {15 n = read (); m = read (); 16 vis [1] = 1; // 1 is not a prime number 17 for (int I = 2; I <= sqrt (n); I ++) 18 for (int j = I * I; j <= n; j + = I) 19 vis [j] = 1; 20 while (m --) 21 {22 int p = read (); 23 if (vis [p] = 1) printf ("No \ n "); 24 else printf ("Yes \ n"); 25} 26 return 0; 27}
But you will find that this code can only get 30 points
It seems that this algorithm is not good enough.
Let's explore his optimization.
In addition, the time complexity of this algorithm: $ O (n * logn) $
Sieve optimized version
Based on the unique decomposition theorem
Each number can be decomposed into prime product forms.
During enumeration, we can continue enumeration only when the current number is a prime number.
This ensures that each prime number is screened out.
1 # include <cstdio> 2 # include <cmath> 3 using namespace std; 4 const int MAXN = 10000001; 5 inline int read () 6 {7 char c = getchar (); int f = 1, x = 0; 8 while (c <'0' | c> '9') {if (c = '-') f =-1; c = getchar ();} 9 while (c> = '0' & c <= '9') x = x * 10 + c-48, c = getchar (); return x * f; 10} 11 int vis [MAXN]; 12 int n, m; 13 int main () 14 {15 n = read (); m = read (); 16 vis [1] = 1; // 1 is not a prime number 17 for (int I = 2; I <= sqrt (n); I ++) 18 if (vis [I] = 0) 19 for (int j = I * I; j <= n; j + = I) 20 vis [j] = 1; 21 while (m --) 22 {23 int p = read (); 24 if (vis [p] = 1) printf ("No \ n "); 25 else printf ("Yes \ n"); 26} 27 return 0; 28}
Indeed, after optimization, this algorithm is much faster.
It can be proved that its complexity is: $ O (n * log ^ {logn}) $
This algorithm is already very good, but for extreme data like 1e7, there is still a risk of being stuck.
Is there a faster screening method?
The answer is yes!
Euler's Sieve
Let's think about the calculation process of the second screening method.
It is not hard to find that for the number 6, it is screened once by 2, and again by 3
The second screen is obviously redundant,
We want to remove this operation.
1 #include<cstdio> 2 #include<cmath> 3 using namespace std; 4 const int MAXN=10000001; 5 inline int read() 6 { 7 char c=getchar();int f=1,x=0; 8 while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();} 9 while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();return x*f;10 }11 int vis[MAXN],prime[MAXN];12 int tot=0;13 int n,m;14 int Euler()15 {16 vis[1]=1;17 for(int i=2;i<=n;i++)18 {19 if(vis[i]==0) prime[++tot]=i;20 for(int j=1;j<=tot&&i*prime[j]<=n;j++)21 {22 vis[i*prime[j]]=1;23 if(i%prime[j]==0) break;24 }25 }26 }27 int main()28 {29 n=read();m=read();30 Euler();31 for(int i=1;i<=m;i++)32 {33 int p=read();34 if(vis[p]==1) printf("No\n");35 else printf("Yes\n");36 }37 return 0;38 }
We will discuss the code in detail.
When $ I $ is a prime number, the product of the two prime numbers must not be screened, which can avoid repeated screening.
When $ I $ is not a prime number
There is a very critical statement in the program.
1 if (I % prime [j] = 0) break;
This statement ensures that only the number not greater than $ prime [j] * I $ can be screened out in this cycle.
In this way, we can ensure that a number is only screened by its smallest prime factor!
This ensures that each number is screened only once.
For example,
Set $ I = 2*3*5 $. You can screen $ I * 2 $, but not $3 * I $.
Because if you can expose $3 * I $,
When $ I _2 = 3*3*5 $, the screening of $2 * I _2 $ is the same as the previous one.
In addition, a chart is provided for your convenience.
This is intuitive.
Let's try to figure out
We can see that the time efficiency of this algorithm is very high!
Time Complexity: strict $ O (n) $
Summary
In general, the second screening method is enough.
The advantage of the third screening method is not only the speed, but also the screening of product functions, such as Euler's function and Mobius function.
I will talk about this later.