线性筛法
Eratosthenes筛法
虽然Eratosthenes筛法并不是线性的,但是它的时间复杂度是O(NloglogN),已经是很快了,是竞赛中最常见的质数筛法,所以在这里简单的提一下:这个方法的核心就是知道得到一个质数后,将i*i~n的合数筛除,这里就直接贴上CODE:
for (int i=2; i<=n; i++) {
if(vis[i]) continue;
prime[++tot]=i;
for(int j=i; j<=n/i; j++) vis[i*j]=1;
}
线性筛法
线性筛法就是O(N)筛质数了,观察Eratosthenes筛法可以发现依旧有很多数被多个质数筛除,为了进一步优化时间复杂度,我们可以让每一个合数都被它最小的质因子筛去,就可以实现O(n)解决。具体怎么做呢?我们维护一个从小到大的质数序列,对于正在扫描的这个数,我们可以进行分类:
1、这个数是质数,因为我们扫描的顺序是从小到大的,所以这个质数必定大于所有已知质数,那我们就可以将这个数与质数序列中的每一个质数相乘的到合数,并筛去这个合数。
2、这个数是合数,我们就可以扫描质数序列,如果扫描到第一个质数满足这个合数是它的倍数,那么这个质数就是它的最小质因子
根据上面的分类我们可以得到线性筛的CODE:
int n=100;
for(int i=2; i<=n; i++) {
if(!vis[i]) prime[++tot]=i;
for (int j=1; j<=tot; j++) {
if(n/i<prime[j]) break; //保证不越界
vis[prime[j]*i] = 1;
if(i%prime[j]==0) break;
}
}
用途:线性筛可以用来求积性函数(暂时只知道这个)。
这里暂且就以phi为例,即φ函数,性质如下
欧拉函数:小于n且与n互素的数个数,记为φ(n)
φ(prime) = prime - 1
先贴上板子
int n=100; for(int i=2; i<=n; i++) { if(!vis[i]) { prime[++tot]=i; phi[i] = i - 1; } for (int j=1; j<=tot; j++) { if(n/i<prime[j]) break; //保证不越界 vis[prime[j]*i] = 1; if (i % prime[j] == 0) { phi[i * prime[j]] = phi[i] * prime[j]; break; } phi[i * prime[j]] = phi[i] * (prime[j] - 1); } }