线性筛法(欧拉筛)

从前有一个素数筛法叫埃拉托斯特尼筛法,它的思想很简单,把1-n以内素数的整数倍的数字划掉,留下的就全是素数,但是它的复杂度是O(NlglgN),对于大量不友好数据会跪,于是线性晒登场了。

#include 
using namespace std;
int prime[1100000],primesize,phi[11000000];
bool isprime[11000000];
void getlist(int listsize)
{
    memset(isprime,1,sizeof(isprime));
    isprime[1]=false;
    for(int i=2;i<=listsize;i++)
    {
        if(isprime[i])prime[++primesize]=i;
         for(int j=1;j<=primesize&&i*prime[j]<=listsize;j++)
         {
            isprime[i*prime[j]]=false;
            if(i%prime[j]==0)break;
        }
    }
}

以上就是线性晒代码,他与埃氏筛法大概有这么几点不同:

①:if(i%prime[j]==0)break;

这句代码保证了每个数最多被筛一次,将时间复杂度降到了线性。

证明如下:prime[]数组中的素数是递增的,当i能整除prime[j],那么i*prime[j+1]这个合数肯定被prime[j]乘以某个数筛掉。
   因为i中含有prime[j],prime[j]比prime[j+1]小,即i=k*prime[j],那么i*prime[j+1]=(k*prime[j])*prime
   [j+1]=k’*prime[j],接下去的素数同理。所以不用筛下去了。因此,在满足i%prime[j]==0这个条件之前以及第一次
   满足改条件时,prime[j]必定是prime[j]*i的最小因子。


大名鼎鼎的线性晒日常筛素数的速度大概是埃氏筛的3-4倍,然而在小数据中却有被完爆的可能QAQ

所以欧拉筛法不只是拿来筛个素数,更重要的一点是线性筛可以用来求解积性函数。

积性函数f(x)应满足f(a×b)=f(a)×f(b),a与b应互素。而完全积性函数则应满足对于任意的a与b,前面的等式应成立。

先上欧拉phi函数:


memset(check,false,sizeof(check));
fai[1] = 1;
int tot = 0;
for(int i = 2 ; i <= N ; i++)
{
	if(! check[i])
	{
		prime[tot++] = i;
		fai[i] = i - 1;
	}
	for(int j = 0 ; j < tot ; j++)
	{
		if(i * prime[j] > N) break;
		check[i * prime[j]] = true;
		if(i % prime[j] == 0){
			fai[i * prime[j]] = fai[i] * prime[j];
			break;
		}
		else	{
			fai[i * prime[j]] = fai[i] * (prime[j] - 1);
		}
	}
}
	
再来个线性筛解莫比乌斯函数:
 
  
memset(check,false,sizeof(check));
mu[1] = 1;
int tot = 0;
for(int i = 2 ; i <= N ; i++)
{
	if(! check[i])
	{
		prime[tot++] = i;
		mu[i] = -1;
	}
	for(int j = 0 ; j < tot ; j++)
	{
		if(i * prime[j] > N) break;
		check[i * prime[j]] = true;
		if(i % prime[j] == 0){
			mu[i * prime[j]] = 0;
			break;
		}
		else	{
			mu[i * prime[j]] = -mu[j];
		}
	}
}
	



 
  




你可能感兴趣的:(数论)