莫比乌斯反演--懵逼反演系列

反演的定义

设有数论函数 f ( n ) , g ( n ) f(n),g(n) f(n),g(n),其中 g ( n ) g(n) g(n)已知
f ( n ) , g ( n ) f(n),g(n) f(n),g(n)满足关系 g ( n ) = ∑ i = 0 n a n , i f ( i ) g(n)=\sum_{i=0}^na_{n,i}f(i) g(n)=i=0nan,if(i)

反演就是利用 g ( n ) g(n) g(n)和已知关系推导出 f ( n ) f(n) f(n)关于 g ( i ) g(i) g(i)的表达
f ( n ) = ∑ i = 0 n b n , i g ( i ) f(n)=\sum_{i=0}^nb_{n,i}g(i) f(n)=i=0nbn,ig(i)


莫比乌斯函数

了解莫比乌斯反演之前肯定要先了解莫比乌斯函数
设正整数 N N N按算术基本定理分解质因数为 N = ∏ i = 1 m p i c i N=\prod_{i=1}^mp_i^{c_i} N=i=1mpici

μ ( N ) = { 0 , ∃ i ∈ [ 1 , m ] , c i > 1 1 , m ≡ 0 ( m o d    2 ) , ∀ i ∈ [ 1 , m ] c i = 1 − 1 , m ≡ 1 ( m o d    2 ) , ∀ i ∈ [ 1 , m ] c i = 1 \mu(N)=\left\{\begin{aligned}0,\exists i\in[1,m],c_i>1 \\ 1,m\equiv 0(\mod 2),\forall i\in[1,m]c_i=1 \\ -1 ,m\equiv 1(\mod 2),\forall i\in[1,m]c_i=1\end{aligned}\right. μ(N)=0,i[1,m],ci>11,m0(mod2),i[1,m]ci=11,m1(mod2),i[1,m]ci=1

即若 N N N含相同质因子,则 μ ( N ) = 0 \mu(N)=0 μ(N)=0
N N N所有质因子各不相等且质因子个数为偶数,则 μ ( N ) = 1 \mu(N)=1 μ(N)=1
N N N所有质因子各不相等且质因子个数为奇数,则 μ ( N ) = − 1 \mu(N)=-1 μ(N)=1

特别的 μ ( 1 ) = 1 \mu(1)=1 μ(1)=1

莫比乌斯函数的性质
  • ∑ d ∣ n μ ( d ) = [ n = 1 ] \sum_{d|n}\mu(d)=[n=1] dnμ(d)=[n=1]

这个性质是接下来证明的重要论据

  • 莫比乌斯函数是积性函数

这个意味着莫比乌斯函数可以用埃式筛或线性筛求解

  • 对任意正整数 N N N, ∑ d ∣ n μ ( d ) d = φ ( n ) n \sum_{d|n}\frac{\mu(d)}{d}=\frac{\varphi(n)}{n} dndμ(d)=nφ(n)

这个挺好玩的,但是没啥用


莫比乌斯反演

常见的莫比乌斯反演有两种形式

  • g ( n ) = ∑ d ∣ n f ( d )   ⇐ ⇒   f ( n ) = ∑ d ∣ n μ ( d ) g ( n d ) g(n)=\sum_{d|n}f(d)\ \Leftarrow \Rightarrow \ f(n)=\sum_{d|n}\mu(d)g(\frac{n}{d}) g(n)=dnf(d)  f(n)=dnμ(d)g(dn)
  • g ( n ) = ∑ n ∣ d f ( d )   ⇐ ⇒   f ( n ) = ∑ n ∣ d μ ( d n ) g ( d ) g(n)=\sum_{n|d}f(d)\ \Leftarrow \Rightarrow \ f(n)=\sum_{n|d}\mu(\frac{d}{n})g(d) g(n)=ndf(d)  f(n)=ndμ(nd)g(d)
形式一证明

f ( n ) = ∑ d ∣ n μ ( d ) g ( n d ) f(n)=\sum_{d|n}\mu(d)g(\frac{n}{d}) f(n)=dnμ(d)g(dn)
= ∑ d ∣ n μ ( d ) ∑ k ∣ n d f ( k ) = ∑ d ∣ n ∑ k ∣ n d μ ( d ) f ( k ) =\sum_{d|n}\mu(d)\sum_{k|\frac{n}{d}}f(k)=\sum_{d|n}\sum_{k|\frac{n}{d}}\mu(d)f(k) =dnμ(d)kdnf(k)=dnkdnμ(d)f(k)
注意到 d , k d,k d,k满足 d ∣ n , k ∣ ( n / d ) d|n,k|(n/d) dn,k(n/d),所以容易得出 k ∣ n , d ∣ ( n / k ) k|n,d|(n/k) kn,d(n/k),继续变换

∑ d ∣ n ∑ k ∣ n d μ ( d ) f ( k ) = ∑ k ∣ n ∑ d ∣ n k f ( k ) μ ( d ) = ∑ k ∣ n f ( k ) ∑ d ∣ n k μ ( d ) \sum_{d|n}\sum_{k|\frac{n}{d}}\mu(d)f(k)=\sum_{k|n}\sum_{d|\frac{n}{k}}f(k)\mu(d)=\sum_{k|n}f(k)\sum_{d|\frac{n}{k}}\mu(d) dnkdnμ(d)f(k)=kndknf(k)μ(d)=knf(k)dknμ(d)

根据前文所述莫比乌斯函数性质一
∑ d ∣ n k μ ( d ) = [ n = k ] \sum_{d|\frac{n}{k}}\mu(d)=[n=k] dknμ(d)=[n=k],带入后得 f ( n ) = f ( n ) ∗ 1 f(n)=f(n)*1 f(n)=f(n)1成立

证毕

形式二证明

证明过程与前面证明类似
f ( n ) = ∑ k = 1 + ∞ μ ( k ) F ( n k ) f(n)=\sum_{k=1}^{+\infty}\mu(k)F(nk) f(n)=k=1+μ(k)F(nk)
= ∑ k = 1 + ∞ μ ( k ) ∑ n k ∣ t f ( t ) =\sum_{k=1}^{+\infty}\mu(k)\sum_{nk|t}f(t) =k=1+μ(k)nktf(t)
= ∑ n ∣ t f ( t ) ∑ k ∣ t n μ ( k ) =\sum_{n|t}f(t)\sum_{k|\frac{t}{n}}μ(k) =ntf(t)kntμ(k)

同样带入性质一得证


莫比乌斯反演的应用

洛谷P3455 [POI2007]ZAP-Queries
对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a,y<=b,并且gcd(x,y)=d
1 ≤ n ≤ 50000 , 1 ≤ d ≤ a , b ≤ 50000 1≤n≤50 000,1≤d≤a,b≤50 000 1n50000,1da,b50000

莫比乌斯反演的经典例题
f ( k ) f(k) f(k)表示满足条件的 ( x , y ) (x,y) (x,y)数量,即 f ( k ) = ∑ i = 1 a ∑ j = 1 b [ g c d ( i , j ) = k ] f(k)=\sum_{i=1}^a\sum_{j=1}^b[gcd(i,j)=k] f(k)=i=1aj=1b[gcd(i,j)=k]
g ( k ) g(k) g(k)表示满足 g c d ( x , y ) m o d    k = = 0 gcd(x,y)\mod k==0 gcd(x,y)modk==0 ( x , y ) (x,y) (x,y)数量 ( x ≤ a , y ≤ b ) (x\leq a,y\leq b) (xa,yb)

那么有 g ( n ) = ⌊ a n ⌋ ⌊ b n ⌋ = ∑ n ∣ k f ( k ) g(n)=\lfloor\frac{a}{n}\rfloor\lfloor\frac{b}{n}\rfloor=\sum_{n|k}f(k) g(n)=nanb=nkf(k)

于是根据上述反演公式得 a n s = f ( d ) = ∑ d ∣ k μ ( ⌊ k d ⌋ ) g ( k ) ans=f(d)=\sum_{d|k}\mu(\lfloor\frac{k}{d}\rfloor)g(k) ans=f(d)=dkμ(dk)g(k)

t = k / d t=k/d t=k/d
∑ t = 1 m i n ( ⌊ a d ⌋ , ⌊ b d ⌋ ) μ ( t ) ⌊ a t d ⌋ ⌊ b t d ⌋ \sum_{t=1}^{min(\lfloor\frac{a}{d}\rfloor,\lfloor\frac{b}{d}\rfloor)}\mu(t)\lfloor\frac{a}{td}\rfloor\lfloor\frac{b}{td}\rfloor t=1min(da,db)μ(t)tdatdb

到这里已经可以 O ( n ) O(n) O(n)处理每次询问,但由于多组询问复杂度还是不太乐观
对于 ⌊ a t d ⌋ ⌊ b t d ⌋ \lfloor\frac{a}{td}\rfloor\lfloor\frac{b}{td}\rfloor tdatdb这一部分用整除分块处理,处理一次询问的时间复杂度为 O ( n ) O(\sqrt n) O(n )

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long lt;
  
lt read()
{
    lt f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}
  
const int maxn=50010;
int T;
int miu[maxn],vis[maxn];
int prim[maxn],cnt;
lt sum[maxn];

void Miu(int n)
{
    miu[1]=1;
    for(int i=2;i<=n;++i)
    {
        if(!vis[i]){ miu[i]=-1; prim[++cnt]=i;}
        for(int j=1;j<=cnt;++j)
        {
            if(prim[j]*i>n) break;
            vis[prim[j]*i]=1;
            if(i%prim[j]==0) break;
            else miu[i*prim[j]]=-miu[i];
        }
    } 
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+miu[i];
}

int main()
{
    T=read(); Miu(maxn-10);
    while(T--)
    {
        lt a=read(),b=read(),d=read();
        
        lt ans=0,lim=min(a/d,b/d);
        int ad=a/d,bd=b/d;
        for(int ll=1,rr;ll<=lim;ll=rr+1)
        {
            rr=min(ad/(ad/ll),bd/(bd/ll));
            ans+=(a/(ll*d))*(b/(ll*d))*(sum[rr]-sum[ll-1]);
        }
        
        printf("%lld\n",ans);
    }
    return 0;
}

换个角度看反演

其实大多时候解反演题并不一定要设出 f ( n ) , g ( n ) f(n),g(n) f(n),g(n)
把莫比乌斯反演公式的推导过程铺开
我们会发现其实就是在想办法构造 ∑ d ∣ n μ ( d ) = [ n = = 1 ] \sum_{d|n}\mu(d)=[n==1] dnμ(d)=[n==1]

那上面这题为例换个方法反演,首先 a n s = ∑ i = 1 a ∑ j = 1 b [ g c d ( i , j ) = d ] ans=\sum_{i=1}^a\sum_{j=1}^b[gcd(i,j)=d] ans=i=1aj=1b[gcd(i,j)=d]
g c d ( x , y ) = 1 gcd(x,y)=1 gcd(x,y)=1,则有 g c d ( x ∗ d , y ∗ d ) = d gcd(x*d,y*d)=d gcd(xd,yd)=d,于是上述式子变形得

∑ x = 1 ⌊ a d ⌋ ∑ y = 1 ⌊ b d ⌋ [ g c d ( x , y ) = 1 ] \sum_{x=1}^{\lfloor\frac{a}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{b}{d}\rfloor}[gcd(x,y)=1] x=1day=1db[gcd(x,y)=1]

现在我们惊喜的发现 [ g c d ( x , y ) = 1 ] [gcd(x,y)=1] [gcd(x,y)=1]可以用莫比乌斯函数性质一做个替换

∑ x = 1 ⌊ a d ⌋ ∑ y = 1 ⌊ b d ⌋ ∑ t ∣ g c d ( x , y ) μ ( t ) \sum_{x=1}^{\lfloor\frac{a}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{b}{d}\rfloor}\sum_{t|gcd(x,y)}\mu(t) x=1day=1dbtgcd(x,y)μ(t)

把枚举约数提前

∑ t = 1 m i n ( ⌊ a d ⌋ , ⌊ b d ⌋ ) ∑ x = 1 ⌊ a d ⌋ ∑ y = 1 ⌊ b d ⌋ μ ( t ) [ t ∣ g c d ( x , y ) ] \sum_{t=1}^{min(\lfloor\frac{a}{d}\rfloor,\lfloor\frac{b}{d}\rfloor)}\sum_{x=1}^{\lfloor\frac{a}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{b}{d}\rfloor}\mu(t)[t|gcd(x,y)] t=1min(da,db)x=1day=1dbμ(t)[tgcd(x,y)]

[ t ∣ g c d ( x , y ) ] = 1 [t|gcd(x,y)]=1 [tgcd(x,y)]=1成立,则 t ∣ x , t ∣ y t|x,t|y tx,ty,所以把枚举 x , y x,y x,y变成枚举 t t t的倍数
最后把 μ ( t ) \mu(t) μ(t)提前

∑ t = 1 m i n ( ⌊ a d ⌋ , ⌊ b d ⌋ ) μ ( t ) ∑ t 1 = 1 ⌊ a d t ⌋ ∑ t 2 = 1 ⌊ b d t ⌋ 1 = ∑ t = 1 m i n ( ⌊ a d ⌋ , ⌊ b d ⌋ ) μ ( t ) ⌊ a t d ⌋ ⌊ b t d ⌋ \sum_{t=1}^{min(\lfloor\frac{a}{d}\rfloor,\lfloor\frac{b}{d}\rfloor)}\mu(t)\sum_{t_1=1}^{\lfloor\frac{a}{dt}\rfloor}\sum_{t_2=1}^{\lfloor\frac{b}{dt}\rfloor}1=\sum_{t=1}^{min(\lfloor\frac{a}{d}\rfloor,\lfloor\frac{b}{d}\rfloor)}\mu(t)\lfloor\frac{a}{td}\rfloor\lfloor\frac{b}{td}\rfloor t=1min(da,db)μ(t)t1=1dtat2=1dtb1=t=1min(da,db)μ(t)tdatdb

竟然得到了完全一样的答案!!

所以这说明不是遇上反演的题就一定要凑出 f , g f,g f,g和公式所述的关系
而是应该思考如何将表达式构造出能利用 ∑ d ∣ n μ ( d ) = [ n = = 1 ] \sum_{d|n}\mu(d)=[n==1] dnμ(d)=[n==1]的形式


继续懵逼反演的应用

BZOJ2301 [HAOI2011]Problem b
对于给定的整数a,b,c,d,k,有多少正整数对x,y,满足a<=x<=b,c<=y<=d,并且gcd(x,y)=k
1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000

和上一题大同小异,加一个容斥即可
如果被卡常的话可以考虑把一些没必要开long long的变量换成int
以及 a / k , b / k a/k,b/k a/k,b/k这种重复计算的可以先处理,可以快很多

lt query(int a,int b)
{
    lt res=0;
    int ak=a/k,bk=b/k,lim=min(a/k,b/k);
    for(int ll=1,rr;ll<=lim;ll=rr+1)
    {
        rr=min(ak/(ak/ll),bk/(bk/ll));
        res+=(lt)(ak/ll)*(bk/ll)*(sum[rr]-sum[ll-1]);
    }
    return res;
}

lt ans=query(b,d)-query(b,c-1)-query(a-1,d)+query(a-1,c-1);

HDU - 1695 GCD
对于给定的整数a,b,c,d,k,有多少正整数对x,y,满足1<=x<=b,1<=y<=d,并且gcd(x,y)=k
(x=i,y=j)与(x=j,y=i)等价
T<=3000,0 < a <= b <= 100,000, 0 < c <= d <= 100,000, 0 <= k <= 100,000

和第一题区别在于去重,由于只有 x < = b , y < = b ( b < d ) x<=b,y<=b(b<d) x<=b,y<=b(b<d)这部分会有重复,所以减去这部分总数的一半
以及注意特判k==0的情况

if(b>d) swap(b,d);
lt ans1=query(b,d,k),ans2=query(b,b,k);
printf("Case %d: %lld\n",cs,ans1-ans2/2);

洛谷P2257 YY的GCD
给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对
T = 10000,N, M <= 10000000

首先这题 f ( k ) , g ( k ) f(k),g(k) f(k),g(k)定义依然同上 (一般看到gcd的题都会想到这么设函数)
回顾上面反演后的式子
f ( d ) = ∑ d ∣ k μ ( ⌊ k d ⌋ ) g ( k ) = ∑ t = 1 m i n ( ⌊ N d ⌋ , ⌊ M d ⌋ ) μ ( t ) ⌊ N t d ⌋ ⌊ M t d ⌋ f(d)=\sum_{d|k}\mu(\lfloor\frac{k}{d}\rfloor)g(k)=\sum_{t=1}^{min(\lfloor\frac{N}{d}\rfloor,\lfloor\frac{M}{d}\rfloor)}\mu(t)\lfloor\frac{N}{td}\rfloor\lfloor\frac{M}{td}\rfloor f(d)=dkμ(dk)g(k)=t=1min(dN,dM)μ(t)tdNtdM

现在考虑将这个式子应用到此题
a n s = ∑ p ∈ p r i m e f ( p ) = ∑ p ∈ p r i m e ∑ p ∣ k μ ( ⌊ k p ⌋ ) g ( k ) = ∑ p ∈ p r i m e ∑ t = 1 m i n ( ⌊ N p ⌋ , ⌊ M p ⌋ ) μ ( t ) ⌊ N t p ⌋ ⌊ M t p ⌋ ans=\sum_{p\in prime}f(p)=\sum_{p\in prime}\sum_{p|k}\mu(\lfloor\frac{k}{p}\rfloor)g(k)=\sum_{p\in prime}\sum_{t=1}^{min(\lfloor\frac{N}{p}\rfloor,\lfloor\frac{M}{p}\rfloor)}\mu(t)\lfloor\frac{N}{tp}\rfloor\lfloor\frac{M}{tp}\rfloor ans=pprimef(p)=pprimepkμ(pk)g(k)=pprimet=1min(pN,pM)μ(t)tpNtpM

T = t p T=tp T=tp,继续变形得

∑ T = 1 m i n ( N , M ) ∑ p ∣ T , p ∈ p r i m e μ ( T p ) ⌊ N T ⌋ ⌊ M T ⌋ = ∑ T = 1 m i n ( N , M ) ⌊ N T ⌋ ⌊ M T ⌋ ∑ p ∣ T , p ∈ p r i m e μ ( T p ) \sum_{T=1}^{min(N,M)}\sum_{p|T,p\in prime}\mu(\frac{T}{p})\lfloor\frac{N}{T}\rfloor\lfloor\frac{M}{T}\rfloor=\sum_{T=1}^{min(N,M)}\lfloor\frac{N}{T}\rfloor\lfloor\frac{M}{T}\rfloor\sum_{p|T,p\in prime}\mu(\frac{T}{p}) T=1min(N,M)pT,pprimeμ(pT)TNTM=T=1min(N,M)TNTMpT,pprimeμ(pT)
于是后面那一坨可以预处理前缀和,每次询问用整除分块处理即可

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long lt;
  
int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}
  
const int maxn=10000010;
int T;
int miu[maxn],vis[maxn];
int prim[maxn],cnt;
lt sum[maxn];

void Miu(int n)
{
    miu[1]=1;
    for(int i=2;i<=n;++i)
    {
        if(!vis[i]){ miu[i]=-1; prim[++cnt]=i;}
        for(int j=1;j<=cnt;++j)
        {
            if(prim[j]*i>n) break;
            vis[prim[j]*i]=1;
            if(i%prim[j]==0) break;
            else miu[i*prim[j]]=-miu[i];
        }
    } 
    for(int i=1;i<=cnt;++i)
    for(int j=1;prim[i]*j<=n;++j) sum[prim[i]*j]+=miu[j];
    for(int i=1;i<=n;++i) sum[i]=sum[i-1]+sum[i];
}

lt query(int n,int m)
{
    lt res=0; int lim=min(n,m);
    for(int ll=1,rr;ll<=lim;ll=rr+1)
    {
        rr=min(n/(n/ll),m/(m/ll));
        res+=(lt)(n/ll)*(m/ll)*(sum[rr]-sum[ll-1]);
    }
    return res;
}

int main()
{
    T=read(); Miu(maxn-5);
    while(T--)
    {
        int n=read(),m=read();
        printf("%lld\n",query(n,m));
    }
    return 0;
}

其他懵逼反演应用推导比较长,戳下面链接看噢
BZOJ2154 || 洛谷P1829 [国家集训队]Crash的数字表格 题解
BZOJ3529 || 洛谷P3312 [SDOI2014]数表 题解
BZOJ3994 || P3327 [SDOI2015]约数个数和 题解

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值