莫比乌斯反演

莫比乌斯反演

前置芝士:数论分块

i=1nni,其中 n1012

可以发现,ni 最多只有 n 种取值,所以只需要枚举每种取值对应 i 的取值范围即可。

ll ans = 0;
for(int i = 1,j;i <= n;i = j+1)
{
    j = n/(n/i);
    ans += (n/i)*(j-i+1);
}

积性函数:

如果函数 f 满足 a,b,gcd(a,b)=1,f(ab)=f(a)f(b),则 f 为积性函数。

  • 欧拉函数:φ(n),即 1n 中与 n 互质的个数。
  • 莫比乌斯函数:μ(i)={1n=1(1)kn=p1p2pk0otherwise
  • 因子函数:d(n),即 n 的因子个数。
  • 除数函数:σ(n)=dnd,即 x 的因子之和。

完全积性函数:

如果函数 f(n) 满足 a,b,f(ab)=f(a)f(b),则 f(n) 为完全积性函数。

  • 常数函数:I(n)=1
  • 恒等函数:Id(n)=n
  • 单位函数:ε(n)=[n=1]

狄利克雷卷积:

(fg)(n)=dnf(d)g(nd)

性质:

  • 交换律:fg=gf

  • 结合律:(fg)h=f(gh)

  • 分配律:(f+g)h=fh+fh

  • 如果 f,g 是积性函数,则 fg 也是积性函数。比如:

    • IdI=σ
    • II=d
    • φI=Id
    • μI=ε

    下面是根据上面推出来的:

    • εf=f,即 ε 与任何函数进行狄利克雷卷积后都是函数本身;

    • φd=φII=IdI=σ

    • εId=IdμIId=φIμId=φ

    • μσ=μIdI=εId=Id

莫比乌斯反演:[n=1]=dnμ(d)

其实莫比乌斯反演还有一种形式:g(n)=dnf(d)f(n)=dnμ(d)d(nd),也可以写成:fI=gf=gμ


证明:μI=ε

n=1 时显然成立,当 n>1 时,设 n=p1c1p2c2pkck,由于有平方因子的数的 μ0,所以只需要证 n=p1p2pkdnμ(nd)=0成立即可。

(1)μI=dnμ(nd)(2)=μ(1)+μ(p1)++μ(pk)+μ(p1p2)+μ(p1p3)++μ(pk1pk)++μ(p1p2pk)(3)=i=0k(1)i(ki)(4)=0

欧拉反演:n=dnφ(d)

证明:φI=Id

n=p1c1p2c2pkck,因为 φ 是积性函数,则只需要证 n=pc 时成立即可。

(5)φ1=dnφ(nd)(6)=i=0cφ(pi)(7)=1+p0×(p1)+p1×(p1)++pc1×(p1)(8)=pc(9)=Id

线性筛 φμ

线性筛分有重复因子和没重复因子两种情况,直接分情况讨论即可。

int p[N],phi[N],mu[N],cnt;
bool isp[N];
ll sphi[N],smu[N];
void init()
{
    phi[1] = mu[1] = 1;
    for(int i = 2;i < N;i++)
    {
        if(!isp[i]){p[++cnt] = i;phi[i] = i-1;mu[i] = -1;}
        for(int j = 1;j <= cnt&&p[j]*i < N;j++)
        {
            int now = i*p[j];
            vis[now] = 1;
            if(i%p[j]==0)
            {
                phi[now] = phi[i]*p[j];mu[now] = 0;
                break;
            }
            phi[now] = phi[i]*(p[j]-1);mu[now] = -mu[i];
        }
    }
    for(int i = 1;i < N;i++)
        sphi[i] = sphi[i-1]+phi[i],smu[i] = smu[i-1]+mu[i];
}

例题

  1. 最基本的应用

i=1nj=1m[gcd(i,j)=1]i=1nj=1mgcd(i,j)T 组数据,n,m2×106,T1000

题太多了,甚至有十倍经验

直接莫比乌斯反演(以下默认 nm):

(10)i=1nj=1m[gcd(i,j)=1]=i=1nj=1mdi,djμ(d)(11)=d=1nμ(d)i=1ndj=1md1(12)=d=1nμ(d)ndmd

(13)i=1nj=1mgcd(i,j)=i=1nj=1mdi,djφ(d)(14)=d=1nφ(d)i=1ndj=1md1(15)=d=1nφ(d)ndmd

发现式子中只有 ndmd,直接数论分块即可,时间复杂度 O(n+Tn)

ll ans1 = 0,ans2 = 0;
for(int i = 1,j;i <= n;i = j+1)
{
    j = min(n/(n/i),m/(m/i));
    ans1 += (smu[j]-sum[i-1])*(n/i)*(m/i);
    ans2 += (sphi[j]-sphi[i-1])*(n/i)*(m/i);
}

总结:莫比乌斯反演最重要的就是处理和式,经常推不出式子了就尝试一下交换和式

  1. P2257 YY的GCD

i=1nj=1m[gcd(i,j)prime]T 组数据,n,m107,T104

考虑枚举 gcd(i,j)

(16)i=1nj=1m[gcd(i,j)prime]=pprimei=1nj=1m[gcd(i,j)=p](17)=pprimei=1npj=1mp[gcd(i,j)=1](18)=pprimed=1npμ(d)npxmpx

枚举 T=px

=T=1nnTmTpT,pprimeμ(Tp)

f(n)=pn,pprimeμ(np),只需要预处理出 f(n) 的前缀和即可。具体的,枚举每一个质数,然后用类似埃式筛的方法求出 f(n)。时间复杂度 O(nloglogn+Tn)

//预处理
for(int i = 1;i <= cnt;i++)
    for(int j = p[i];j < N;j += p[i])
        f[j] += mu[j/p[i]];
for(int i = 1;i < N;i++)f[i] += f[i-1];
//计算
for(int i = 1,j;i <= min(n,m);i = j+1)
{
    j = min(n/(n/i),m/(m/i));
    ans += (f[j]-f[i-1])*(n/i)*(m/i);
}
  1. [P3327 SDOI2015] 约数个数和

d(n)n 的约数个数,求 i=1nj=1md(ij)T 组数据,T,n,m5000

考虑转化 d(ij),将 ij 的因子与 ij 的因子一一对应。如果 ij 的因子 k 中有一个因子 pci 中有 paj 中有 pb,则 ca+b。 那么:

  • 如果 ca,那么在 i 中选择 pa
  • 如果 c>a,那么在 j 中选择 pca

所以如果在 i 中选择一个因子 x,在 j 中选择一个因子 ygcd(x,y)=1,则 x,y 一定对应一个 ij 的因子。所以 d(ij)=xiyj[gcd(x,y)=1]

(19)i=1nj=1md(ij)=i=1nj=1mxiyj[gcd(x,y)=1](20)=x=1ny=1mnxmy[gcd(x,y)=1](21)=x=1ny=1mnxmydx,dyμ(i)(22)=d=1nμ(i)x=1ndx=1mdnxdmyd(23)=d=1nμ(i)(x=1ndnxd)(y=1mdmyd)

发现括号里面的东西可以预处理,令 f(n)=i=1nni,则原式等于 d=1nμ(i)f(nd)f(md),数论分块即可。时间复杂度 O(nn+Tn)

//预处理
for(int i = 1;i < N;i++)
    for(int j = 1,k;j <= i;j = k+1)
    {
        k = i/(i/j);
        f[i] += (k-j+1)*(i/j);
    }
//计算
for(int i = 1,j;i <= min(n,m);i = j+1)
{
    j = min(n/(n/i),m/(m/i));
    ans += (smu[j]-smu[i-1])*f[n/i]*f[m/i];
}
  1. P1829 Crash的数字表格

求:i=1nj=1mlcm(i,j)T 组数据,n,m107,T104

因为 lcm(i,j)=ijgcd(i,j)=gcd(i,j)×igcd(i,j)×jgcd(i,j),枚举 gcd(i,j)

i=1nj=1mlcm(i,j)=d=1nd×i=1ndj=1md[gcd(i,j)=1]×ij

为了单独计算后半边式子,记 :

sum(n,m)=d=1nd×i=1nj=1m[gcd(i,j)=1]×ij

另外,记 S(n)=i=1ni=n(n+1)2,那么:

(24)sum(n,m)=i=1nj=1mij×di,djμ(d)(25)=d=1nμ(d)×d2×i=1ndj=1mdij(26)=d=1nμ(d)d2×S(nd)S(md)

其实到这里就可以数论分块套数论分块做了,时间复杂度 O(Tn34),但事实上原式还可以优化。

d=1nd×sum(nd,md)=d=1nd×k=1ndμ(k)k2×S(ndk)S(mdk)

d 乘进去:

d=1nk=1ndμ(k)k×dk×S(ndk)S(mdk)

先枚举 T=dk

T=1nS(nT)S(mT)×TkTμ(k)k

发现后半部分其实是可以预处理的,只需要求出 TkTμ(k)k 的前缀和即可。令函数 f(n)=knμ(k)k,不难证明 f 是积性函数,所以可以在线性筛的时候顺便求。具体的,如果在用 ii×px 有平方因子,即 pi,因为 μ(n)n 有平方因子时为 0,所以 f(i×p)=f(i);如果没有平方银子,根据积性函数的性质,有 f(i×p)=f(i)×f(p)。时间复杂度 O(Tn)

//预处理
void init()
{
    f[1] = 1;
    for(int i = 2;i < N;i++)
    {
        if(!vis[i])p[++cnt] = i,f[i] = mod+1-i;
        for(int j = 1;j <= cnt&&i*p[j] < N;j++)
        {
            int now = i*p[j];vis[now] = 1;
            if(i%p[j]==0){f[now] = f[i];break;}
            f[now] = f[i]*f[p[j]]%mod;
        }
    }
    for(int i = 1;i < N;i++)f[i] = (f[i-1]+f[i]*i)%mod;
}
//计算
for(int i = 1,j;i <= n;i = j+1)
{
    j = min(n/(n/i),m/(m/i));
    (ans += (f[j]-f[i-1]+mod)*S(n/i)%mod*S(m/i)) %= mod;
}
  1. [P3312 SDOI2014] 数表

给定 n,m,a,求 i=1nj=1mσ(gcd(i,j))[σ(gcd(i,j))a]T 组数据,n,m105,T2×104

先考虑没有 a 的限制:

(27)ans=i=1nj=1mσ(gcd(i,j))(28)=d=1nσ(d)i=1ndj=1md[gcd(i,j)=1](29)=d=1nσ(d)i=1ndμ(i)ndimdi

枚举 T=di

(30)ans=T=1nnTmTdTσ(d)μ(Td)

f(x)=dxσ(d)μ(xd),此时只有当 σ(d)a 时,才会对 f(x) 产生贡献。

于是可以按 a 从小到大对询问排序,每次暴力加入所有 σ(d)ad,并更新 f(x)。由于求答案还需要知道 f 的前缀和,所以用树状数组维护即可。每个数插入的次数为调和级数,而插入一次时间复杂度为 O(logn),所以总时间复杂度就是 O(nlog2n+Tnlogn)

杜教筛

介绍:

杜教筛可以在 O(n23) 的时间复杂度中求出一类积性函数的前缀和。假设 f 是一个积性函数,如果能找到另一个积性函数 g 使得 gfg 的前缀和都能快速求出,那么就能用杜教筛求出 f 的前缀和。

比如:

  • 可以在 O(1) 的时间内求出 1ε 的前缀和,而 μI=ε,所以可以用杜教筛求出 μ 的前缀和。
  • 可以在 O(1) 的时间内求出 1Id 的前缀和,而 φI=Id,所以可以用杜教筛求出 φ 的前缀和。

杜教筛:

现在要求积性函数 f 的前缀和,令 S(n)=i=1nf(i)

再找一个积性函数 g,则 fg 的前缀和为:

(31)i=1n(fg)(i)=i=1ndif(d)g(id)(32)=d=1ng(d)i=1ndf(i)(33)=d=1ng(d)S(nd)

接着考虑 g(1)S(n) 等于什么,发现:

(34)g(1)S(n)=i=1ng(i)S(ni)i=2ng(i)S(ni)(35)=i=1n(fg)(i)i=2ng(i)S(ni)

此时只需要找一个积性函数 g 使得 gfg 的前缀和都可以快速求出,就可以数论分块递归来求了。

伪代码:

ll sum_g(ll n);//g的前缀和
ll sum_fg(ll n);//f*g的前缀和
ll sum_f(ll n)
{
    ll ans = sum_fg(n);
    for(ll i = 2,j;i <= n;i = j+1)
    {
        j = n/(n/i);
        ans -= (sum_g(j)-sum_g(i-1))*sum_f(n/i);
    }
    return ans;
}

杜教筛是数论分块里面递归,时间复杂度可以看作 O(n34),具体咋证的可以看以下式子感性理解:

i=1nO(i)+O(ni)=O(n34)

其实可以预处理出前 m 个答案,然后再用杜教筛,时间复杂度就是:

i=1nmO(ni)=O(nm)

一般为了平均,当 m=n23 时,时间复杂度也是 O(n23)

μ,φ 的前缀和

  • μI=ε,而 I(n) 的前缀和就是 nε(n) 的前缀和就是 1
  • φI=Id,而 Id(n) 的前缀和就是 n(n+1)2

代码中 smu,sphi 是提前筛好的 μφ 的前缀和,Smu,Sphi 是记忆化。

ll sum_mu(int n)
{
    if(n < N)return smu[n];
    if(Smu[n])return Smu[n];
    ll ans = 1;
    for(ll i = 2,j;i <= n;i = j+1)
    {
        j = n/(n/i);
        ans -= (j-i+1)*sum_mu(n/i);
    }
    return Smu[n] = ans;
}
ll sum_phi(int n)
{
    if(n < N)return sphi[n];
    if(Sphi[n])return Sphi[n];
    ll ans = n*(n+1ll)/2;
    for(ll i = 2,j;i <= n;i = j+1)
    {
        j = n/(n/i);
        ans -= (j-i+1)*sum_phi(n/i);
    }
    return Sphi[n] = ans;
}

扩展:

f(n)=φ(i)×i 的前缀和。

g=Id,则:

(36)(fg)(n)=dn(φ(d)×d)×nd(37)=ndnφ(d)(38)=n2

所以 fg 的前缀和就是 n(n+1)(2n+1)6

PN 筛

咕咕咕

Min25 筛

咕咕咕

posted @   max0810  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示