线性筛法

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);
            }
        }       

 

posted @ 2018-07-21 15:30  惜梦园  阅读(15)  评论(0)    收藏  举报