笔记:莫比乌斯反演

摘自peng-ym的博客

整除分块

(sum_{i=1}^n lfloor {frac n i} floor)

朴素 (O(n)) , 整除分块 (O(sqrt n))

显然有许多连续的 (lfloor {frac n i} floor) 值是一样的。可以发现,每个块的最后一个数是 (frac n {lfloor frac n i floor })

for(int l=1,r;l<=n;l=r+1){
    r=n/(n/l);
    ans+=(r-l+1)*(n/l);
}

有时推出的柿子不一定是裸的板子,可能与一些积性函数相乘( (mu),(phi)...),

此时需要对这些函数统计前缀和,这样跳过一个区间时就乘上一个区间的函数值。(?)

积性函数&狄利克雷卷积

%George1123

以后我也会卷啦!

积性函数:

定义:

如果 (gcd(x,y)=1) 并且 (f(xy)=f(x)·f(y))(f(n)) 是积性函数。

特别的,对于任意 (x,y) 满足 (f(xy)=f(x)·f(y)) 的是完全积性函数。

e.g.

完全积性

  • 一元函数:(epsilon (x)=[x=1]) 是积性函数的单位元(可以随便卷在一起和去掉)

  • 常数函数:(1(x)=1) 好像也有用字母 (I) 的。

  • 单位函数:(id(x)=x)

积性

  • 欧拉函数:(phi(x)=sum_{i=1}^x [gcd(x,i)=1])

  • 约数个数函数:(d(x)=sum_{d|n} 1)

  • 约数和函数: (sigma(n)=sum_{d|n} d)

  • 莫比乌斯函数:……

性质:

如果 (f(x)) 是积性函数,那么 (h(x)) 也是:

[h(x)=f(x^p)\ h(x)=f^p(x) ]

如果 (f(x))(g(x)) 是积性函数,那么 (h(x)) 也是:

[h(x)=f(x)·g(x)\ h(x)=sum_{d|x} f(d)·g(frac x d) ]

狄利克雷卷积

定义:

两个数论函数 (f)(g) 的狄利克雷卷积 ((f*g))

[(f*g)(x)=sum_{d|x} f(d)·g(frac x d) ]

性质:

满足交换律和结合律和分配率。自己卷自己是自己。

莫比乌斯反演

莫比乌斯函数

  • 符号:(mu) .

  • 定义:

    [ mu(d)=left{ egin{array}{rcl} 1 & & {d=1}\ (-1)^k & & {d=Pi_{i=1}^k p_i 且 p_i 为互异素数时}\ 0 & & {d 的一个质因子次数ge 2}\ end{array} ight. ]

  • 性质:

    1. 对于任意 (nin {N}^+)(mu*1=epsilon (sum_{d|n} mu(d)=[n=1])) 常用性质

    考虑非0的 (mu(d)) 的和。
    (n)(k) 个质因子,有 (2^k) 个因子,有 (C_{k,i}) 个的有 (i) 个质因子,
    (ans=C(k,0)-C(k,1)+C(k,2)-C(k,3)+...=sum_{i=0}^k (-1)^iC(k,i))
    二项式定理: ((x+y)^n=sum C(n,i)x^iy^{(n-i)})
    (ans=(-1+1)^k=0^k)
    得证。

    1. 对于任意 (nin N^+),

      [sum_{d|n} frac {mu(d)} d=frac {phi(n)} n ]

      Proof

      [首先有结论sum_{d|n} phi(d)=n(id=phi*I)\ 证明:\ frac 1 n,frac 2 n,frac 3 n,...,frac n n \化简这些分数 分母是 d (d|n)\ 每个分母d对应的分子个数就是 phi(d) ]

      [id=phi*I\ id*mu=phi*I*mu\ id*mu=phi*epsilon\ id*mu=phi\ phi=id*mu\ phi(n)=sum_{d|n} mu(d)*frac n d\ sum_{d|n} phi(d)=n(id=phi*I) ]

  • 代码

    void getmu(int n){
        mu[1]=1;
        for(int i=2;i<=n;i++){
            if(!vis[i]) { p[++cnt]=i; mu[i]=-1; }
            for(int j=1;j<=cnt&&p[j]*i<=n;j++){
                vis[p[j]*i]=1;
                if(i%p[j]==0) break;
                else mu[p[j]*i]=-mu[i];
            }
        }
    }
    

    (O(n))

莫比乌斯反演

莫比乌斯反演定理

(F(n))(f(n)) 是定义在 (N) 上的两个函数,并且满足条件

[F(n)=sum_{d|n} f(d) ]

有结论:

[f(n)=sum_{d|n} mu(d)F(lfloor {frac n d} floor) ]

Proof:

[sum_{d|n}mu(d)F(lfloorfrac{n}{d} floor)\=sum_{d|n}mu(d)sum_{i|lfloorfrac{n}{d} floor}f(i)\ =sum_{i|n}f(i)sum_{d|lfloorfrac{n}{i} floor}mu(d)\=f(n) ]

Proof2:

噫!好!让我们用狄利克雷卷积来证明一下。

已知

[F(n)=sum_{d|n} f(d) ]

求证

[f(n)=sum_{d|n} mu(d)·F(frac n d) ]

[转化一下:\ 已知:\ F(n)=sum_{d|n} f(d)\ F(n)=sum_{d|n} f(d)·1(frac n d)\ F=f*1\ 求证:\ f(n)=sum_{d|n} mu(d)·F(frac n d)\ f(n)=mu *F\ 证明:\ F*mu=f*1*mu=f*epsilon=f\ 比上面那坨好多了qwq ]

莫比乌斯反演有另一种可能更好用的形式:

条件:

[F(n)=sum_{n|d} f(d) ]

结论:

[f(n)=sum_{n|d}mu(lfloor frac{d}{n} floor)F(d) ]

证明:
(k=frac d n)

(f(n)=sum_{k=1}^{inf} mu(k)F(nk)=sum_{k=1}^{inf} mu(k) sum_{nk|t} f(t)=sum_{n|t} f(t) sum_{k|frac t n} mu(k))

当且仅当 (frac t n =1) ,即 (t=n) 时, (sum_{k|frac t n}mu(k)=1)

(sum_{n|t} f(t) sum_{k|frac t n}mu (k)=f(n))


$F(n)=sum_{n|d} f(d) $

(f(n)=sum_{n|d}mu(lfloor frac{d}{n} floor)F(d))

习题

LG2257 - YY的GCD

给定 (N,M) ,求 (1le x le N,1le yle M)(gcd(x,y)) 为质数的 ((x,y)) 有多少对?

(ans=sum_{x=1}^n sum_{y=1}^m [gcd(x,y)=prime])

第一道莫反不会做 列完这个柿子就壮烈牺牲了。

(f(d))(gcd(i,j)=d) 的个数

(F(n))(gcd(i,j)=n)(n) 的倍数的个数。

(套路)

(f(d)=sum_{x=1}^n sum_{y=1}^m [gcd(x,y)=d])

(F(n)=sum_{n|d} f(d)=lfloor frac N n floor lfloor frac M n floor)

(f(n)=sum_{n|d}mu(lfloor frac{d}{n} floor)F(d))

(ans=sum_{pin prime} f(p))

(ans=sum_{pin prime} sum_{p|d}mu(lfloor frac{d}{p} floor)F(d))

(ans=sum_{pin prime} sum_{d=1}^{min(frac n p,frac m p)} mu(d)F(dp))

(ans=sum_{pin prime} sum_{d=1}^{min(frac n p,frac m p)} mu(d)lfloor frac n {dp} floor lfloorfrac m {dp} floor)

(ans=sum_{T=1}^{min(n,m)} lfloor frac n T floor lfloor frac m T floor imes(sum_{t|T,tin prime} mu(lfloor frac T t floor)))

最后一坨东西可以预处理 前面那坨整除分块

void getmu(){
    mu[1]=1;
    for(int i=2;i<=N;i++){
        if(!fl[i]) p[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&p[j]*i<=N;j++){
            fl[p[j]*i]=1;
            if(i%p[j]==0) continue;
            mu[i*p[j]]=-mu[i];
        }
    }
    for(int i=1;i<=cnt;i++)
        for(int j=1;p[i]*j<=N;j++)
            f[p[i]*j]+=mu[j];//T=p[i]*j t=p[i]
    for(int i=1;i<=N;i++) sum[i]=sum[i-1]+f[i];
    return;
}//预处理前面那坨
long long solve(int a,int b){
    long long ans=0;
    for(int l=1,r;l<=a;l=r+1){
        r=min(a/(a/l),b/(b/l));
        ans+=1ll*(sum[r]-sum[l-1])*(a/l)*(b/l);
    }
    return ans;
}//预处理后面那坨
int main(){
    int t; scanf("%d",&t);
    getmu();
    while(t--){
        scanf("%d%d",&n,&m);
        if(n>m) swap(n,m);
        printf("%lld
",solve(n,m));
    }
    return 0;
}

草,题解说入门的不适合做这题(

LG2522 - [HAOI2011]Problem b

(n) 次询问,每次询问有多少个数对 ((x,y)) 满足 (ale xle b,cle yle d) 且 $gcd(x,y)=k $ 所有东西都是 (5 imes 10^4)

草 这好像是前一题的低配啊,这确定没搞反吗。

[sum_{x=a}^b sum_{y=c}^d [gcd(x,y)=k]\ sum_{x=1}^b sum_{y=1}^d [gcd(x,y)=k]+sum_{x=1}^a sum_{y=1}^c [gcd(x,y)=k]-sum_{x=1}^b sum_{y=1}^c [gcd(x,y)=k]-sum_{x=1}^a sum_{y=1}^d [gcd(x,y)=k]\ 即求\ sum_{x=1}^N sum_{y=1}^M [gcd(x,y)=k]\ 我们从上一题得到:\ 设 f(d) 为 gcd(i,j)=d 的个数\ F(n) 为 gcd(i,j)=n 和 n 的倍数的个数。\ f(d)=sum_{x=1}^n sum_{y=1}^m [gcd(x,y)=d]\ F(n)=sum_{n|d} f(d)=lfloor frac N n floor lfloor frac M n floor\ f(n)=sum_{n|d}mu(lfloor frac{d}{n} floor)F(d)\ f(n)=sum_{n|d}mu(lfloor frac{d}{n} floor)lfloor frac N d floor lfloor frac M d floor\ f(n)=sum_{t=1}^{min(N,M)}mu(t)lfloor frac N {nt} floor lfloor frac M {nt} floor\ 然后求解前面那坨用预处理,后面那坨整除分块。 O(N+Tsqrt n) ]

void getmu(){
    mu[1]=1;
    for(int i=2;i<=N;i++){
        if(!fl[i]) p[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&p[j]*i<=N;j++){
            fl[p[j]*i]=1;
            if(i%p[j]==0) continue;
            mu[i*p[j]]=-mu[i];
        }
    }
    for(int i=1;i<=N;i++) sum[i]=sum[i-1]+mu[i];
    return;
}
long long solve(int a,int b,int k){
    if(a>b) swap(a,b);
    long long ans=0;
    for(int l=1,r;l<=a;l=r+1){
        r=min(a/(a/l),b/(b/l));
        ans+=1ll*(sum[r]-sum[l-1])*(a/(1ll*l*k))*(b/(1ll*l*k));
    }
    return ans;
}
int main(){
    int t; scanf("%d",&t);
    getmu();
    while(t--){
        int a,b,c,d,k;
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
        printf("%lld
",solve(b,d,k)-solve(a-1,d,k)-solve(b,c-1,k)+solve(a-1,c-1,k));
    }
    return 0;
}

显然顺序搞反了。。

[LG3455 - POI2007]ZAP-Queries

倒序开题,双倍经验,这是好的。这是前一道题的前置题。是 (a=1,b=1) 的情况。

[LG3327 - SDOI2015]约数个数和

(d(x))(x) 的约数个数,给定 (n,m) ,求 (sum_{i=1}^n sum_{j=1}^m d(ij))

[ans=sum_{i=1}^n sum_{j=1}^m d(ij)=sum_{i=1}^n sum_{j=1}^m sum_{x|i} sum_{y|j} [gcd(x,y)=1]\ 原因:gcd(x,y) 不为1时,x=ad,y=bd,xy=abd^2,在 x=ab,y=d^2时已被筛了一次。\ ans=sum_{i=1}^n sum_{j=1}^m sum_{x|i} sum_{y|j} [gcd(x,y)=1]\ =sum_{x=1}^n sum_{y=1}^m lfloor frac n x floor lfloor frac m y floor [gcd(x,y)=1]\ =sum_{i=1}^n sum_{j=1}^m lfloor frac n i floor lfloor frac m j floor [gcd(i,j)=1]\ 设 f(d)=sum_{i=1}^n sum_{j=1}^m lfloor frac n i floor lfloor frac m j floor [gcd(i,j)=d]\ F(x)=sum_{n|d} f(d)=sum_{i=1}^n sum_{j=1}^m lfloor frac n i floor lfloor frac m j floor [x|gcd(i,j)] =sum_{i=1}^{frac n x} sum_{j=1}^{frac m x} lfloor frac n {ix} floor lfloor frac m {jx} floor\ \ans=f(1)=sum_{d=1}^{min(n,m)}mu(d)F(d)=sum_{x=1}^{min(n,m)} mu(x) sum_{i=1}^{frac n x} sum_{j=1}^{frac m x} lfloor frac n {xi} floor lfloor frac m {xj} floor\ 然后整除分块预处理 s(x)=sum_{i=1}^x lfloor frac x i floor O(1) 询问 F(d)\ 这样可以O(Tsqrt n) ]

void init(){
    for(int i=1;i<=N;i++){
        for(int l=1,r;l<=i;l=r+1){
            r=i/(i/l);
            s[i]+=1ll*(r-l+1)*(i/l);
        }
    }//预处理s

    mu[1]=1;
    for(int i=2;i<=N;i++){
        if(!vis[i]) p[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&p[j]*i<=N;j++){
            vis[i*p[j]]=1;
            if(i%p[j]==0) continue;
            mu[i*p[j]]=-mu[i];
        }
    }
    for(int i=1;i<=N;i++) sum[i]=sum[i-1]+mu[i];
    return;
}
int main(){
    int t; scanf("%d",&t); 
    init();
    while(t--){
        int n,m; scanf("%d%d",&n,&m);
        if(n>m) swap(n,m);
        ll ans=0;
        for(int l=1,r;l<=n;l=r+1){
            r=min(n/(n/l),m/(m/l));
            ans+=1ll*(sum[r]-sum[l-1])*s[n/l]*s[m/l];
        }//分块求
        printf("%lld
",ans);
    }
    return 0;
}

LG1829 [国家集训队]Crash的数字表格 / JZPTAB

(ans=sum_{i=1}^n sum_{j=1}^m lcm(i,j)) (n,mle 10^7)

[\ans=sum_{i=1}^n sum_{j=1}^m frac {i imes j} {gcd(i,j)} \=sum_{d=1}^{min(n,m)} (d imessum_{i=1}^{frac n d} sum_{j=1}^{frac m d} [gcd(i,j)=1] imes i imes j) \∵sum_{d|n} mu(d)=[n=1] \∴ ans=sum_{d=1}^{min(n,m)} (d imes sum_{i=1}^{frac n d} sum_{j=1}^{frac m d} (sum_{x|gcd(i,j)} mu(x)) imes i imes j ) \sum_{d=1}^{min(n,m)} d imes sum_{x=1}^{min(frac n d,frac m d)} mu(x) sum_{i=1}^{frac n d} sum_{j=1}^{frac m d} i imes j imes[x|gcd(i,j)] \sum_{d=1}^{min(n,m)} d imes sum_{x=1}^{min(frac n d,frac m d)} mu(x) sum_{xu=1}^{frac n d} sum_{xv=1}^{frac m d} x^2uv \提出x^2 \sum_{d=1}^{min(n,m)} d imes sum_{x=1}^{min(frac n d,frac m d)} mu(x)x^2sum_{xu=1}^{frac n d} sum_{xv=1}^{frac m d} uv \sum_{d=1}^{min(n,m)} d imes sum_{x=1}^{min(frac n d,frac m d)} mu(x)x^2(sum_{u=1}^{frac n {dx}}u) imes (sum_{v=1}^{frac m {dx}} v)\ \sum_{d=1}^{min(n,m)} d imes sum_{x=1}^{min(frac n d,frac m d)} mu(x)x^2 s(frac n {dx}) imes s(frac m {dx})\ \mu(x)x^2 用前缀和优化,枚举d,整除分块求出后面一坨。 \ 积分算出时间复杂度近似 O(n) 草不知道怎么搞的。 ]

void init(){
    mu[1]=1;
    for(int i=2;i<=N;i++){
        if(!vis[i]){ mu[i]=-1; p[++cnt]=i; }
        for(int j=1;j<=cnt&&p[j]*i<=N;j++){
            vis[p[j]*i]=1;
            if(i%p[j]==0) continue;
            mu[p[j]*i]=-mu[i];
        }
    }
    for(int i=1;i<=N;i++)
        sum[i]=(sum[i-1]+1ll*mu[i]%mod*i%mod*i%mod)%mod;
    return;
}
int calc(int x){ return (1ll*x*(x+1)/2)%mod; }
int main(){
    scanf("%d%d",&n,&m);
    if(n>m) swap(n,m);
    init();
    for(int d=1;d<=n;d++){
        int a=n/d,b=m/d,ret=0;
        for(int l=1,r;l<=a;l=r+1){
            r=min(a/(a/l),b/(b/l));
            ret=(ret+1ll*(sum[r]-sum[l-1])*calc(n/(d*l))%mod*calc(m/(d*l))%mod)%mod;
        }
        ans=(ans+1ll*ret*d%mod)%mod;
    }
    printf("%d
",(ans+mod)%mod);
    return 0;
}

SP5971 LCMSUM - LCM Sum

(T) 次询问,每次询问给定 (n) ,求 (sum_{i=1}^n lcm(i,n))

[sum_{i=1}^n frac {i imes n} {gcd(i,n)}\ =nsum_{i=1}^n frac {i} {gcd(i,n)}\ =nsum_{d|n} sum_{i=1}^n frac {i} {d} [gcd(i,n)=d]\ =nsum_{d|n} sum_{i=1}^{frac n d} i·[gcd(i,frac n d)=1]\ sum_{i=1}^{t} i·[gcd(i,t)=1] 表示[1,t]中与t互质的数的和。\ 有结论t>1为 frac {phi(d)d} 2,d=1时为1(草我就不会这个) \ 证明:d>1时,与d互质的数总是成对出现。(i与d互质,则d-i与d互质,和为d,有frac {phi(d)} 2 对。\ ans=nsum_{d|n} frac {phi(frac n d)frac n d} 2\ 设f(d)=sum_{d|n} frac {phi(frac n d)frac n d} 2\ 对于每个 1le dle n 将frac {phi(d)·d} 2加入f(dj) 询问时再乘n \复杂度O(T+nlog n) ]

void init(){
    phi[1]=1;
    for(int i=2;i<=N;i++){
        if(!vis[i]) phi[i]=i-1,p[++cnt]=i;
        for(int j=1;j<=cnt&&p[j]*i<=N;j++){
            vis[p[j]*i]=1;
            if(i%p[j]==0){
                phi[p[j]*i]=phi[i]*p[j];
                break;
            }
            phi[p[j]*i]=phi[i]*(p[j]-1);
        }
    }
    for(int i=1;i<=N;i++){
        ll tmp=1ll*phi[i]*i/2;
        if(i==1) tmp=1;
        for(int j=1;j*i<=N;j++) f[j*i]+=tmp;
    }
    return;
}
int main(){
    scanf("%d",&t);
    init();
    while(t--){
        scanf("%d",&n);
        printf("%lld
",1ll*f[n]*n);
    }
    return 0;
}

咕咕咕

qaqaq
原文地址:https://www.cnblogs.com/zdsrs060330/p/14093705.html