欧拉筛扩展

欧拉筛可以认为是埃筛的升级版。

埃筛的缺陷在于对于一个合数,有可能被筛多次,例如30=2*15=3*10=5*6。不难发现,如果我们用它的最小质因子来筛选,就可以保证每个合数只被筛选一次,这便是欧拉筛法。

而欧拉筛的扩展就在于它可以在筛素数的同时求积性函数。

积性函数定义:对于一个函数f(x)满足:若gcd(a,b)=1,则f(a*b)=f(a)*f(b)。

求欧拉函数

int prime[maxn];
int mindiv[maxn];
int phi[maxn];
int cnt;
void solve(int n)
{
    for(int i=2;i<=n;i++)
    {
        if(!mindiv[i])
        {
            mindiv[i]=prime[++cnt]=i; phi[i]=i-1;
        }
        for(int j=1,k;j<=cnt&&(k=i*prime[j])<=n;j++)
        {
            mindiv[k]=prime[j];
            if(i%prime[j]==0)
            {
                phi[k]=phi[i]*prime[j];
                break;
            }
            phi[k]=phi[i]*(prime[j]-1);
        }
    }
}

求最小质因数的指数

int prime[maxn];
int mindiv[maxn];
int minexp[maxn];
int cnt;
void solve(int n)
{
    for(int i=2;i<=n;i++)
    {
        if(!mindiv[i])
        {
            mindiv[i]=prime[++cnt]=i;
            minexp[i]=1;
        }
        for(int j=1,k;j<=cnt&&(k=i*prime[j])<=n;j++)
        {
            mindiv[k]=prime[j];
            if(i%prime[j]==0)
            {
                minexp[k]=minexp[i]+1;
                break;
            }
            minexp[i]=1;
        }
    }
}

求约数个数

int prime[maxn];
int mindiv[maxn];
int minexp[maxn];
int d[maxn];
int cnt;
void solve(int n)
{
    for(int i=2;i<=n;i++)
    {
        if(!mindiv[i])
        {
            mindiv[i]=prime[++cnt]=i;
            minexp[i]=1;
            d[i]=2;
        }
        for(int j=1,k;j<=cnt&&(k=i*prime[j])<=n;j++)
        {
            mindiv[k]=prime[j];
            if(i%prime[j]==0)
            {
                minexp[k]=minexp[i]+1;
                d[k]=d[i]/(minexp[i]+1)*(minexp[k]+1);
                break;
            }
            minexp[i]=1;
            d[k]=d[i]*d[prime[j]];
        }
    }
}

求约数个数还有个野路子

for(int i=1;i<=n;i++)
    for(int j=i;j<=n;j+=i)
        d[j]++;

虽然速度不及欧拉筛,但它简单好写啊。

求约数和

int prime[maxn];
int mindiv[maxn];
int sumd[maxn];
int f1[maxn];//f1[i]=sigma(mindiv[i]^(0..minexp[i])) 
int f2[maxn];//f2[i]=mindiv[i]^minexp[i]
int cnt;
void solve(int n)
{
    for(int i=2;i<=n;i++)
    {
        if(!mindiv[i])
        {
            mindiv[i]=prime[++cnt]=i;
            sumd[i]=1+i;
            f1[i]=1+i;
            f2[i]=i;
        }
        for(int j=1,k;j<=cnt&&(k=i*prime[j])<=n;j++)
        {
            mindiv[k]=prime[j];
            if(i%prime[j]==0)
            {
                f2[k]=f2[i]*prime[j];
                f1[k]=f1[i]+f2[k];
                sumd[k]=sumd[i]/f1[i]*f1[k];
                break;
            }
            sumd[k]=sumd[i]*sumd[prime[j]];
            f1[k]=1+prime[j];
            f2[k]=prime[j];
        }
    }
}

求莫比乌斯函数

int prime[maxn];
int mindiv[maxn];
int miu[maxn];
int cnt;
void solve(int n)
{
    miu[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!mindiv[i])
        {
            mindiv[i]=prime[++cnt]=i;
            miu[i]=-1;
        }
        for(int j=1,k;j<=cnt&&(k=i*prime[j])<=n;j++)
        {
            mindiv[k]=prime[j];
            if(i%prime[j]==0)
            {
                miu[k]=0;
                break;
            }
            miu[k]=-miu[i];
        }
    }
}

以上都是比较常见的积性函数,用筛法求积性函数的本质是根据积性函数的定义和运算式,利用筛法的特点,构造合适的转移方法。

这里给出基本模板

void solve(int n)
{
    v[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!v[i])
        {
            prime[++cnt]=i;
            .....//素数的积性函数值
        }
        for(int j=1,k;j<=cnt&&(k=i*prime[j])<=n;j++)
        {
            v[i*prime[j]]=1;
            .....//公共部分
            if(i%prime[j]==0)
            {
                .....//k和k的最小素因子的处理
                break;
            }
            .....//k和比k的最小素因子小的素数的处理
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值