线性筛素数、欧拉函数

判断一个数n是否是素数,众所周知可以用O(sqrt(n))的方法。

但是如果要求很多个数,这个方法就不太好了。(比如所有小于n的数,复杂度就是O(n1.5)。)

埃拉托斯特尼筛法,大家都听说过。从2到n,去掉每个数的倍数,剩下来的就是质数。

不过这个方法会重复删除,比如6是2、3的倍数,会被删2次,因子越多,删的次数就越多。

改进之后的线性筛保证每个数只被最小的质因子删,所以是O(n)的。

#include<cstdio>
#include<cstring>
#define MAXN 100005
#define MAXL 1299710
int prime[MAXN];
int check[MAXL];

int tot = 0;
memset(check, 0, sizeof(check));
for (int i = 2; i < MAXL; ++i)
{
  if (!check[i])
  {
    prime[tot++] = i;
  }
  for (int j = 0; j < tot; ++j)
  {
    if (i * prime[j] > MAXL)
    {
      break;
    }
    check[i*prime[j]] = 1;
    if (i % prime[j] == 0)
    {
      break;
    }
  }
}
View Code

 (代码来自:https://www.cnblogs.com/grubbyskyer/p/3852421.html)

tot是计数用的,prime保存质数,check是判断是否是质数。

1.任意一个合数 A = p1p2...pn,(其中p1<=p2<=...<=pn) ,i=p2p3...pn时会删掉。

2.A只会被p1删掉。若i是prime[j]的倍数,A不会被p[j+1]删掉,当i=A/p[j+1]时,i%p[j+1]==0,break。如果不退出,A就被p[j+1]删了。

可以看出,这个方法需要额外的prime数组。而埃氏筛不必要。

顺便可以求欧拉函数

#include<cstdio>
#include<cstring>
#define MAXN 100005
#define MAXL 1299710
int prime[MAXN];
int check[MAXL];
int phi[MAXL];
int tot = 0;
phi[1] = 1;
memset(check, 0, sizeof(check));
for (int i = 2; i < MAXL; ++i)
{
  if (!check[i])
  {
    prime[tot++] = i;
    phi[i] = i - 1;
  }
  for (int j = 0; j < tot; ++j)
  {
    if (i * prime[j] > MAXL)
    {
      break;
    }
    check[i*prime[j]] = 1;
    if (i % prime[j] == 0)
    {
      phi[i*prime[j]] = phi[i] * prime[j];
      break;
    }else
    {
      phi[i*prime[j]] = phi[i] * (prime[j]-1);
    }
  }
}
View Code

n为质数,phi(n)=n-1

n为合数,进行质因数分解。n=p1k1p2k2...pnkn

猜你喜欢

转载自www.cnblogs.com/azureice/p/euler-sieve.html
今日推荐