一般的埃氏筛
int vis[maxn]
void shai()
{
memset(vis, 0, sizeof(vis));
vis[1] = 1;
for (int i = 2; i< maxn; i++) //不包括maxn
{
if (!vis[i])
{
for (int j = 2; j * i < maxn; j++;)
//一开始写的for(int j=2;j*i<manx;j*=i)
vis[i * j] = 1;
//该循环可以优化为for(int j=i*i;j<maxn;j+=i)因为在在之前已经筛掉了(2-i-1)*j的数
}
}
}
例如12
一开始的时候当i为2的时候已经筛去了,但是当i等于4的时候未优化版会再筛一遍,而优化之后是从4*4开始筛,就不会再遍历12了。
线性筛
可以发现对于埃氏筛就算优化之后也会遍历重复的点,例如12一开始2遍历过了,3也会遍历,所以就不是最优的解,所以就有了线性筛,这一种比埃氏筛更快的解。线性筛原理:是任何一个数t都可以用一个最大因数i(不包括自身)乘以另外一个素数a(质数)来得到(也就是网上常说的任何一个数都可以分解成一个数来乘以另外一个质数),但是素数(质数)有很多,要一个一个遍历嘛?事实是不用的,我们只用遍历比i最小质因数还小或者和i最小质因数相等的质数即可。
原因:
1.为什么是质数?
因为这个数a如果是合数的话,按照线性筛的原理, a可以分解为另外的一个因数i1*a1,那么t=i*a=i*i1*a1,i*i1>i所以i不是t最大因数,所以a要为质数。
2.为什么要比i的最小质因数小或者等于?
如果这个数a比i的最小质因数大,假设i=p1*p2*p3*p4……(多次运用线性筛原理把t的所有数都化成质数相乘,p1为最小的质因数,从左到右递增),因为a比p1大,那么存在i1=a*p2*p3*p4……(就是用a来替换其中的p1),因为a>p1所以i1>i,所以i还不是t的最大因数。所以数a要比i的最小质因数要小或者等于。
const int maxn = 20;
int vis[maxn];
int pri[maxn];
int cnt;
void shai()
{
memset(vis, 0, sizeof(vis));
vis[1] = 1;
cnt = 0;
for (int i = 2; i<maxn; i++)
{
if (!vis[i])
pri[cnt++]=i;
for (int j = 0; j < cnt && i * pri[j] < maxn; j++)
{
vis[i * pri[j]] = 1;
if (i % pri[j] == 0) //找到i的最小质因数并且使用其来标记之后不在循环
break;
}
}
}
然后就得到了时间复杂度为O(20)的线性筛法