关于欧拉函数与莫比乌斯函数等一系列积性函数的线性筛

Posted LLppdd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于欧拉函数与莫比乌斯函数等一系列积性函数的线性筛相关的知识,希望对你有一定的参考价值。

为什么要学习不同的筛法?

原因很简单,因为通常当我们需要运用欧拉函数等一系列函数的时候,我们会采取提前预处理的方法来提高我们的效率。既然要提升效率,那么我们就需要尽量用优秀一下的方法来完成我们的要求。

线性筛的出发点是什么?

我们利用的最重要的性质就是它的积性。那么积性是什么?我们分为积性和完全积性。积形函数具有如下的性质:

\(F( a * b ) = F( a ) * F( b ) ( gcd( a , b ) = 1 )\)

而完全积性函数就是没有互质这个限定条件

\(F( a * b ) = F( a ) * F( b )\)

那么由欧拉函数,莫比乌斯函数的定义很容易的就可以得到它们是一个积性函数。因此,自然而然就可以想到,我们可以通过求出两个互质的数 a , b 的函数值 来推出 a * b 对应的函数值

所以就有了一下这个筛法:


/*  线性筛求出莫比乌斯函数的值 
    利用积性函数的性质  */ 

mu[1] = 1;
for(int i = 1; i <= n; ++i)
{
    if(not_prime[i] == 0)
    {
        tot++;
        prime[tot] = i; mu[i] = -1; 
    }
    for(int j = 1; prime[j] * i <= n; ++j)
    {
        not_prime[prime[j] * i] = 1;
        if(i % prime[j] == 0)
        {
            mu[prime[j] * i] = 0;
            break;
        }
        mu[prime[j] * i] = -mu[i];
    }
} 

/* 线性筛欧拉函数 */ 
void get_eular()    
{    
    pnum = 0;  
    for(int i = 2; i < MAX; i++)    
    {    
        if(!noprime[i])    
        {    
            p[pnum ++] = i;    
            phi[i] = i - 1;    
        }    
        for(int j = 0; j < pnum && i * p[j] < MAX; j++)    
        {    
            noprime[i * p[j]] = true;    
            if(i % p[j] == 0)    
            {    
                phi[i * p[j]] = phi[i] * p[j];    
                break;    
            }    
            phi[i * p[j]] = phi[i] * (p[j] - 1);    
        }    
    }    
} 

现在我们来解释一下这个代码:
首先,这一系列函数分为两个部分,质数与非质数。

那么对于质数,我们应该先进行一次特殊处理。原因有两个:

(1) 质数的计算方法不方便使用积性函数的性质,理应特殊处理(注:不同函数有对应的方法)

(2) 质数处理了以后,我们要通过它去求得更多的函数值。

对于非质数,运用积性函数的性质进行计算

那么则是循环语句中最关键的几句话

你每循环到一个 i ,就应该算出 i 的倍数的对应的函数值。又因为质数的性质,只有当 i 是一个质数的倍数的时候它们才可能不互质。所以这是一个临界条件。

既然这样,我们再讨论一下为什么能够break?

我们担心的无非就是会不会有遗漏?显然我们不需要担心这一点,原因很简单:

每一个数一定会被它最小的质因数给计算到,而刚好在计算以后 ———— break;

所以不会有遗漏的情况

因此有了这种常用的线性筛法

以上是关于关于欧拉函数与莫比乌斯函数等一系列积性函数的线性筛的主要内容,如果未能解决你的问题,请参考以下文章

线性筛

欧拉筛线性处理莫比乌斯函数

数论入门——莫比乌斯函数,欧拉函数,狄利克雷卷积,线性筛,莫比乌斯反演,杜教筛

线性筛+求莫比乌斯函数‘

模板 - 数论 - 线性筛

线性筛-euler,强大O(n)