线性筛求积性函数

线性筛求积性函数

(更新中)

定理证明

积性函数都可用线性筛法求解
一个大于1的数n可以写成 n=aipi, 而 aipi 之间互质,由于积性函数的性质,所以f(x)=faipi=f(aipi)

线性筛

void init()
{
    for (int i = 2; i < N; i ++)
    {
        if (!st[i]) 
        {
            prime[cnt ++] = i;
            // 1
        }
        for (int j = 0; prime[j] * i <= n; j ++)
        {
            st[prime[j] * i] = true;
            if (i % prime[j] == 0)
            {
                // 2
                break;
            }
            // 3
        }
    }
}

线性筛的原理就不解释了,我们要知道的是每个数是被自己最小的质因子筛掉的就行,这里我们看1,2,3三个地方分别是什么含义。

标号1是质数的时候。

标号2是被最小的质数筛掉,但是这个数中这个质因子出现次数>1,即存在 i|prime[j]2,

标号3和2最大的区别就是,标号3的位置的 iprime[j] 互质。互质可以通过用积性函数的定理去相乘。所有函数都是 f[iprime[j]]=f[i]f[prime[j]]

那么接下来分别考虑每个函数在这三种情况时候的函数就可以轻松写出用质数筛求他们的方法。

线性筛求欧拉函数

欧拉函数的定义是: 小于或等于n的正整数中与n互质的数的数目

那么很快可以知道n为质数,也就是上述的1位置是 φ(n)=n1

3位置上面说过 f[iprime[j]]=f[i]f[prime[j]]

对于2的位置上,我们先设p是n最小质因子,a=n/p。在 1 到 a 中和 a 互质的数是 φ(a)1, a 和 x不互质, 所以 a 和 x + a 也一定互质, 那么在 a+1 到 2a 的范围内和 a 互质的数的个数也是 φ(a)1,所以 φ(n)=φ(a)p

代码如下

void init()
{
    phi[1] = 1;
    for (int i = 2; i < N; i ++) 
    {
        if (!st[i]) 
        {
            prime[cnt ++] = i;
            phi[i] = i - 1;
            // 1
        }
        for (int j = 0; prime[j] * i <= n; j ++)
        {
            st[prime[j] * i] = true;
            if (i % prime[j] == 0)
            {
                phi[i * prime[j]] = phi[i] * prime[j];
                // 2
                break;
            }
            phi[i * prime[j]] = phi[i] * phi[prime[j]];
            // 3
        }
    }
}

线性筛求莫比乌斯函数

μ(n)={1n=10p, p2n(1)k k 是质因子个数 

从函数就可以看出,n是质数的话就是 -1, μ(n)=0 的时候对应线性筛 标号2 的地方,标号3的地方每次多乘以一个质因子,所以 μ[iprime[j]]=μ[i]

代码:

void init()
{
    mu[1] = 1;
    for (int i = 2; i < N; i ++) 
    {
        if (!st[i]) 
        {
            prime[cnt ++] = i;
            mu[i] = -1;
            // 1
        }
        for (int j = 0; prime[j] * i <= n; j ++)
        {
            st[prime[j] * i] = true;
            if (i % prime[j] == 0)
            {
                mu[i * prime[j]] = 0;
                // 2
                break;
            }
            mu[i * prime[j]] = -mu[i];
            // 3
        }
    }
}

线性筛求约数个数

首先我们用式子表示一下n的约数个数, n=p1a1p2a2...pkak, 所以n的约数个数就是 (a1+1)(a2+1)...(ak+1), 如果 x=yp, 那么他们的约数个数就是(ap+1)/(ap+2), ap 代表质数p的指数。因为线性筛中每个数都是被自己最小的质因子筛掉,所以只需要额外开个数组存每个数的最小质因子的数量就行。
我们用d数组来记录约数个数, 用num数组来记录最小质因子的个数。
标号1质数的部分
d[i]=2,num[i]=1.
标号2的地方是
num[iprime[j]]=num[i]+1,d[iprime[j]]=d[i]/(num[i]+1)(num[iprime[j]]+1)
标号3的地方是
num[iprime[j]]=1,d[iprime[j]]=d[i]d[prime[j]]

void init()
{
    d[1] = 1;
    for (int i = 2; i < N; i ++) 
    {
        if (!st[i]) 
        {
            prime[cnt ++] = i;
            d[i]=2, num[i] = 1;
            // 1
        }
        for (int j = 0; prime[j] * i <= n; j ++)
        {
            st[prime[j] * i] = true;
            if (i % prime[j] == 0)
            {
                // 2
                num[i * prime[j]] = num[i] + 1;
                d[i * prime[j]] = d[i] * (num[i * prime[j]] + 1) / (num[i] + 1);
                break;
            }
            // 3
            num[i * prime[j]] = 1;
            d[i * prime[j]] = d[i] * d[prime[j]]
        }
    }
}

线性筛求约数和

这个和求约数个数差不多, 我们先来看约数和是如何表示的。
n=p1a1p2a2...pkak, n的约数和就是 (1+pi+pi2+...+piai) 用等比数列求和可以化简,那么我们要记录的就是每个数最小质因子的等比数列。

我们用sp数组记录最小质因子的等比数列, 用sd数组记录约数和。
标号2的部分,sp[iprime[j]]=sp[i]prime[j]+1,sd[iprime[j]]=sd[i]/sp[i]sp[iprime[j]];

代码如下:

void init()
{
    sp[1] = 1;
    for (int i = 2; i < N; i ++) 
    {
        if (!st[i]) 
        {
            prime[cnt ++] = i;
            d[i]=2, num[i] = 1;
            sd[i] = sp[i] = i + 1;
            // 1
        }
        for (int j = 0; prime[j] * i <= n; j ++)
        {
            st[prime[j] * i] = true;
            if (i % prime[j] == 0)
            {
                // 2
                sp[i * prime[j]]=sp[i] * prime[j] + 1;
                sd[i * prime[j]]=sd[i] / sp[i] * sp[i * prime[j]];
                break;
            }
            // 3
            sd[i * prime[j]] = sd[i] * sd[prime[j]];
            sp[i * prime[j]] = 1 + prime[j];
        }
    }
}
posted @   からし  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示