筛法

之前一直觉得筛法不重要来着,自从一道题因为死在了筛法上后(没有选择合适的筛法,导致TLE)。。。

  1. 问n以内有多少个素数(n<=1e6)

埃氏筛法
时间复杂度O(n*loglogn)
内容:从2开始往后扫,表中留下来的最小数字是m,此时m是质数,将m的倍数全筛去。

int sieve(int n)
{
    int tot=0;
    for(int i=0;i<=n;i++) vis[i]=0;
    for(int i=2;i<=n;i++)
    {
        if(!vis[i])
        {
            prime[tot++]=i;
            for(int j=i*i;j<=n;j+=i) vis[j]=1;
        }
    }
    return tot;
}

但是我们发现会有一些重复删除的情况,比如12,会被2*6删一次,也会被3*4删一次。

优化之后,时间复杂度为O(n)(这里叫做优化筛)

void eselet(int n)
{
    for(int i=0;i<=n;i++) vis[i]=0;
    for(int i=2;i<=n;i++)
    {
        if(!vis[i])
        {
            prime[tot++]=i;
        }
        for(int j=0;j*i;
            if(k>n) break;
            vis[k]=1;
            if(!i%prime[j]) break;
        }
    }
}

当前值i=p1p2p3…pn(p1<=p2<=p3<=..<=pn)*一个不大于i的素数prime[j],如果i是质数中不包括这个prime[j],那么i*prime[j]之前就没有出现过。prime[j]==p1,那么就跳出。
因为如果i=2*3=6,2*2*3标记,如果2*3*3标记了,那么i=9,3*3*2又会算一遍.

证明:1.不会重复筛
     2.筛出了所有合数

1.证明
种1:当i是质数的时候,prime[j]*i没有出现过。
种2:当i=p2*...*pn(p2<=...<=pn),设p1=prime[j],那么i*p1=p1*p2...pn,是没有出现过的,因为不会有其他的会组成i*p1

2.证明
一个数唯一分解为:n=p1p2p3...pn(n为合数),那么当i=p2p3...pn的时候,会被筛掉

2.给定整数a和b,请问区间[a,b)内有多少个素数
(a < b<=1e12, b-a<=1e6)

这个不能直接用上面的方法,首先数组太大了,然后也会超时。
用区间筛法

首先,b以内的最小质因数一定不超过sqrt(b).如果有了sqrt(b)以内的素数表的话,就可以用埃氏筛法了。

void segment_sieve(LL n)
{
    for(int i=0;i*i0;
    for(int i=0;i0;

    for(int i=2;(LL)i*iif(!small[i])
        {
            for(int j=i*i;(LL)j*j1;//筛[2,sqrt(b))
            for(LL j=(a+i-1)/i*i;j1;//筛[a,b)
        }
    }
}

//为什么不用优化筛优化,因为这样的话不一定到的了b

3。求n以内所有数的欧拉值
求单个欧拉值,n,要将n的质因数都算出来。

这里是求一个范围内的所有值,单个单个算会超时。用筛法求,这里用和上面的埃氏筛法很像
当前质数是谁的质因数,然后产生影响。
时间复杂度O(nloglogn)

void phi_table(int n)
{
    for(int i=2;i<=n;i++) phi[i]=0;
    phi[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!phi[i])
        {
            for(int j=i;j<=n;j+=i)
            {
                if(phi[j]==0) phi[j]=j;
                phi[j]=phi[j]/i*(i-1);
            }
        }
    }
}

4.求1-n内所有的莫比乌斯函数

d=p1*p2*p3...唯一分解
f(d)=   1  (p1p2p3..pn为互异素数,n为偶数或者d为1)
       -1 (p1p2p3..pn为互异素数,n为奇数)
        0 (其他)

求f(d),我们要看d是有哪些质数组成的。但是一个一个求会超时。

这里我们用的是优化筛

void mobious()
{
    int tot=0;
    miu[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!vis[i])
        {
            prime[tot++]=i;
            miu[i]=-1;
        }
        for(int j=0;j*i;
            if(k>maxn) break;
            vis[k]=1;
            if(i%prime[j]) miu[k]=-miu[i];
            else break;
        }
    }
}

你可能感兴趣的:(math)