筛法
筛素数的常用手段:
1、Eratosthenes 筛法
复杂度:O(n log (log n))
从小到大找到一个素数,筛掉所有它的倍数。
代码:
1 void Prim(int n) 2 { 3 //Eratosthenes筛选法 4 memset(check,false,sizeof(check)); 5 int tot = 0; 6 for(int i = 2;i <= n;i ++) 7 if(!check[i]) 8 { 9 prim[tot++] = i; 10 for(int j = 2*i;j <= n;j += i) 11 check[j] = true; 12 } 13 }
2、Euler 筛法(重要!!!)
复杂度:O(n)
鉴于前者算法的优化,因为上面的算法一个非素数可能会被多个质因数筛多次,浪费了,所以优化掉这个,只用一个数最小的质因数排除(筛掉)这个数字。
1 void Euler_prim(int n) 2 { 3 //欧拉筛选法 避免上面筛选法中的重复筛选 4 memset(check,false,sizeof(check)); 5 int tot = 0; 6 for(int i = 2;i <= n;i ++) 7 { 8 if(!check[i]) prim[tot ++] = i; 9 for(int j = 0;j < tot;j ++) //遍历已经找到的素数 10 { 11 if(i * prim[j] > n) break; //后面相乘已经超出 n 的范围,没有查找的必要了 12 check[i * prim[j]] = true; //表示这个数字不是素数 13 if(i % prim[j] == 0) break; 14 } 15 } 16 }
重点解释下 if (i%prim[j]==0) break 这句话:
因为prim[j]是i的最小质因数了,如果这时候继续筛下去,下一个数为i*prim[j+1],因为 i=prim[j]*k,对于这个数来说最小质因数是prim[j],而这时却要用prim[j+1]来筛,则与我们要达到的要求、效果违背,这个数肯定会在以后被Prim[j]筛掉,所以直接break就行了,后面的肯定也会被prim[j]筛掉。
(不知道这样理解对不对。。。)
fighting fighting fighting !!!