莫比乌斯反智学习笔记

 

莫比乌斯反演

前言

 

莫比乌斯反演是数论中的重要内容。对于一些函数$f(n)$,如果很难直接求出它的值,而容易求出其$g(n)$(倍数和或约数和),那么可以通过莫比乌斯反演简化运算,求得$f(n)$的值。

开始学习莫比乌斯反演前,我们需要一些前置知识:整除分块、积性函数、Dirichlet 卷积、莫比乌斯函数。

太毒瘤了

 整除分块

对于形似$\sum_{k}^{n} \lfloor\frac{n}{k}\rfloor  \times ……$的表达式,显而易见,$\forall x  = \lfloor\frac{n}{k}\rfloor存在[l,r](l<=r)且\forall i\in [l,r]满足x=\lfloor\frac{n}{i}\rfloor$,那么可以根据$x$将表达式分块计算,并且$\forall i,R_{i}=L_{i+1}-1$,可以用以下代码迅速处理出。时间复杂度$O(\sqrt{n})$。

for(int i=1,r;i<=n;i=r+1)
{
  r=_min(n/(n/i),m/(m/i));
}

积性函数

定义:$gcd(a,b)=1$且$f(ab)=f(a)f(b)$,则函数$f$为积性函数。

性质:若$f(x)$和$g(x)$为积性函数,则以下函数均为积性函数:

$$\begin{eqnarray}h(x) & & = & f\left(x^{p}\right) \\h(x) & & = & f^{p}(x) \\h(x) & & = & f(x) g(x) \\h(x) & & = & \sum_{d \mid x} f(d) g\left(\frac{x}{d}\right)\end{eqnarray}$$

积性函数例子:

$$\begin{array}{l} \text{约数个数函数}\qquad d(n) = \sum_{d \mid n} 1 &\\ \text{约数和函数}\qquad \sigma(n) = \sum_{d \mid n} d &\\ \text{约数k次幂函数}\qquad \sigma_{k}(n) = \sum_{d \mid n} d^{k} &\\ \text{欧拉函数}\qquad \varphi(n) = \sum_{i = 1}^{n}[\operatorname{gcd}(i, n) = 1] &\\ \text{莫比乌斯函数}\qquad \mu(n) = \left\{ \begin{eqnarray} 1 & n = 1 &\\ (-1)^{k} & c_{1,2, \cdots, k} = 1 \quad\left(n = \prod_{i = 1}^{k} p_{i}^{c_{i}}\right)&\\ 0 & c_{i}>1 \end{eqnarray}\right. \end{array}$$

Dirichlet 卷积

又称狄利克雷卷积,实质上是一种定义新运算。\begin{eqnarray}f*g(n)=\sum_{d|n}^{n}f(d)g(\frac{n}{d} )\end{eqnarray}.*为运算符卷。满足交换结合律分配。

莫比乌斯函数

简化定义:

$$\mu(n) = \left\{ \begin{eqnarray} 1 & n = 1 &\\ (-1)^{k} & \qquad k为n不同质因子个数&\\0 & n含有平方因子 \end{eqnarray}\right.$$


 

公式

$$\begin{eqnarray}\varepsilon  =  \mu * 1 \Longleftrightarrow \varepsilon(n)  =  \sum_{d \mid n} \mu(d) \\d =  1 * 1 \Longleftrightarrow d(n)  =  \sum_{d \mid n} 1 \\\sigma  =  \mathrm{id} * 1 \Longleftrightarrow \sigma(n)  =  \sum_{d \mid n} d \\\varphi = \mu * \mathrm{id} \Longleftrightarrow \varphi(n)  =  \sum_{d \mid n} d \cdot \mu\left(\frac{n}{d}\right) \\f(n)=\sum_{d n} g(d) \Longleftrightarrow g(n)=\sum_{n \mid d} f(d) \mu\left(\frac{d}{n}\right) \\\sum_{d \mid n} f(n) \mu\left(\frac{n}{d}\right)=\sum_{d \mid n}\left(\sum_{k \mid d} g(k)\right) \mu\left(\frac{n}{d}\right) \\\end{eqnarray}$$


 

证明

 咕咕咕


 

例题

  1. 洛谷P1390公约数的

  $$\begin{eqnarray} &\sum_{i = 1}^{n}\sum _{j = 1}^{n}\gcd (i,j)~~~~~~~~~~~~~~~~~~\\& =\sum_{k=1}^{n}k\sum_{i = 1}^{n}\sum_{j = 1}^{n}\left [\gcd(i,j)=k \right ]\\& =\sum_{k=1}^{n}k\sum_{i=1}^{\frac{n}{k} }\sum_{j = 1}^{\frac{n}{k} }\left [\gcd(i,j)=1 \right ]\\& =\sum_{k=1}^{n}k\sum_{i=1}^{\frac{n}{k} }\sum_{j = 1}^{\frac{n}{k} }\varepsilon \left  (\gcd(i,j)\right)~~~~\\& \because \varepsilon(n)=\sum_{d|n}\mu(d)~~~~~~~~~~~~~~~~~~~~\\& \therefore \varepsilon\left (\gcd(i,j)\right)=\sum_{d|\left(\gcd(i,j)\right)}\mu(d)\\& =\sum_{k=1}^{n}k\sum_{i=1}^{\frac{n}{k} }\sum_{j=1}^{\frac{n}{k}}\sum_{d|\gcd(i,j)}\mu(d)\\& =\sum_{k=1}^{n}k\sum_{d=1}^{n}\mu(d)\sum_{i=1}^{\frac{n}{k}}[d|i]\sum_{j=1}^{\frac{n}{k}} [d|j]\\& \because \sum_{j=1}^{\frac{n}{k}}[d|j]=\lfloor\frac{n}{kd}\rfloor \\&  \sum_{i=1}^{\frac {n}{k}}[d|j]=\lfloor\frac{n}{kd}\rfloor\\& \therefore 原式=\sum_{k=1}^{n}k\sum_{d=1}^{n}\mu(d)\lfloor\frac{n}{kd}\rfloor\cdot \lfloor \frac{n}{kd}\rfloor\\& T{\color{Red}->} kd\\& =\sum_{T=1}^{n}\sum_{k|T}k\mu(\frac{T}{k} )\lfloor\frac{n}{T}\rfloor\lfloor\frac{n}{T}\rfloor\\& \because id*\mu(T)=\sum_{k|T}id(k)\mu(\frac{T}{k})=\sum_{k|T}k\mu(\frac{T}{k})\\& \therefore 原式=\sum_{T=1}^{n}\times  (id*\mu(T))\lfloor\frac{n}{T}\rfloor\lfloor\frac{n}{T}\rfloor\\& \because id*\mu(T)=\varphi (T)\\& \therefore 原式=\sum_{T=1}^{n}\varphi (T)\lfloor\frac{n}{T}\rfloor\lfloor\frac{n} {T}\rfloor\\& \end{eqnarray}$$

 

 

所以可以整除分块算出值,然后减去,再去掉重复的gcd(i,j)和gcd(j,i),即除以2

#include<bits/stdc++.h>
using namespace std;
const int N=5000000;
int cnt,zhi[N];
bool he[N];
long long p[N],ans,sum[N],n;
int main()
{
    p[1]=1;
    scanf("%lld",&n);
    for(long long i=2;i<=n;i++)
    {
        if(he[i]==0)
        {
            p[i]=i-1;
            zhi[++cnt]=i;
        }
        for(int j=1;j<=cnt&&i*zhi[j]<=n;j++)
        {
            he[i*zhi[j]]=true;
            if(i%zhi[j]==0)
            {
                p[i*zhi[j]]=p[i]*zhi[j];
                break;
            }
            else
            {
                p[i*zhi[j]]=p[i]*p[zhi[j]];
            }
        }
    }
    for(int i=1;i<=n;i++)
        sum[i]+=sum[i-1]+p[i];
    //整除分块
    for(int i=1,r;i<=n;i=r+1)
    {
        r=n/(n/i);
        ans+=(sum[r]-sum[i-1])*(n/i)*(n/i);
    }
    ans-=n*(n+1)/2;
    ans/=2;
    printf("%lld\n",ans);
    return 0;
}

  2.YY的GCD

$$\begin{eqnarray} \sum_{i=1}^{n}\sum_{j=1}^{j}[\gcd(i,j)==prime] &\\ \sum_{d=1}^{n}[d=prime]\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{m}{d}}[\gcd(i,j)=1] &\\ \sum_{d=1}^{n}[d=prime]\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{m}{d}}\varepsilon(\gcd(i,j)) &\\ \sum_{d=1}^{n}[d=prime]\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{m}{d}}\sum_{k|gcd(i,j)}*\mu(k) &\\ \sum_{d=1}^{n}[d=prime]\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{m}{d}}\sum_{k|i,k|j}*\mu(k) &\\\because i,j为k的倍数 &\\ \therefore 原式=\sum_{d=1}^{n}[d=prime]\sum_{k=1}^{\frac{n}{d}}*\mu(k)\lfloor\frac{n}{kd}\rfloor \lfloor\frac{m}{kd}\rfloor &\\{\color{Red} T->kd} 则原式=\sum_{T=1}^{n}\lfloor\frac{n}{T}\rfloor \lfloor\frac{m}{T}\rfloor \sum_{d|T}[d=prime]*\mu(\frac{T}{d}) &\\\end{eqnarray}$$

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define LL long long
LL mu[10000010];int flag[10000010],prime[10000010],cnt,f[10000010],sum[10000010];
void sieve() {
    mu[1]=1;
    for (int i=2;i<=10000000;i++)
    {
        if (!flag[i])
            prime[++cnt]=i,mu[i]=-1;
        for (int j=1;j<=cnt&&i*prime[j]<=10000000;j++)
        {
            flag[i*prime[j]]=1;
            if (i%prime[j]==0) break;
            mu[i*prime[j]]=-mu[i];
        }
    }
    
    for (int i=1;i<=cnt;i++)
        for (int j=1;prime[i]*j<=10000000;j++)
            f[j*prime[i]]+=mu[j];
    for (int i=1;i<=10000000;i++)
        sum[i]=sum[i-1]+f[i];
}
LL solve(int a,int b) {
    LL ans=0;
    if (a>b) swap(a,b);
    for (int l=1,r=0;l<=a;l=r+1) {
        r=min(a/(a/l),b/(b/l));
        ans+=(LL)(sum[r]-sum[l-1])*(LL)(a/l)*(LL)(b/l);
    }
    return ans;
}
int main() {
    sieve();
    int n,m,T;scanf("%d",&T);
    while (T--) {
        scanf("%d%d",&n,&m);
        if (n>m) swap(n,m);
        printf("%lld\n",solve(n,m));
    }
}

  3.约数个数和

  $$\begin{eqnarray}\sum_{i=1}^{n}\sum_{j=1}^{m}d(ij) &\\d(ij)=\sum_{x|i}\sum_{y|j}\sum_{d|\gcd(i,j)}\mu(d) &\\=\sum_{d|i,d|j}\mu(d)\sum_{x|\frac{i}{d}}\sum_{x|\frac{j}{d}}1 &\\=\sum_{d|i,d|j}\mu(d)d(\frac{i}{d})d(\frac{j}{d}) &\\原式=\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{d|i,d|j}\mu(d)d(\frac{i}{d})d(\frac{j}{d}) &\\=\sum_{d=1}^{n}\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{m}{d}}\mu(d)d(i)d(j) &\\=\sum_{d=1}^{n}\mu(d)\sum_{i=1}^{\frac{n}{d}}d(i)\sum_{j=1}^{\frac{m}{d}}d(j) &\\\end{eqnarray}$$

#include<bits/stdc++.h>
using namespace std;
const int N=50005;
inline int read(){
    int s=0,w=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
    while(isdigit(ch)){s=(s<<1)+(s<<3)+ch-'0';ch=getchar();}
    return s*w;
}
inline int _min(int a,int b){ return a<b?a:b; }
int n,m,T,zhi[N],d[N],mu[N],cnt,t[N];
long long ans;
bool he[N];
void deal(){ for(int i=1,r;i<=n;i=r+1) r=_min(n/(n/i),m/(m/i)),ans+=1ll*d[n/i]*d[m/i]*(mu[r]-mu[i-1]); }
int main(){
    mu[1]=d[1]=1;he[0]=he[1]=true;
    for(int i=2;i<N;i++){
        if(he[i]==0){
            zhi[++cnt]=i; mu[i]=-1;
            d[i]=2; t[i]=1;
        }
        for(int j=1;j<=cnt&&zhi[j]*i<N;j++){
            he[i*zhi[j]]=true;
            if(i%zhi[j]==0){
                d[i*zhi[j]]=d[i]/(t[i]+1)*(t[i]+2);
                t[i*zhi[j]]=t[i]+1;
                break;
            }
            else{
                d[i*zhi[j]]=d[i]*2;
                t[i*zhi[j]]=1;
                mu[i*zhi[j]]=-mu[i];
            }
        }
    }
    for(int i=2;i<N;i++){
        mu[i]+=mu[i-1];
        d[i]+=d[i-1];
    }
    T=read();
    while(T--){
        ans=0;
        n=read();m=read();
        if(n>m) swap(n,m);
        deal();
        printf("%lld\n",ans);
    }
    return 0;
}

 

  4.数字表格

 

 (图源SpadeA261

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1000005;
int n,m,mu[N],zhi[N],cnt;
bool he[N];
long long sum[N],ans,f[N],mod=1e9+7,sum_inv[N],f_inv[N];
int _max(int a,int b)
{
    return a>b?a:b;
}
int _min(int a,int b)
{
    return a<b?a:b;
}
inline int read()
{
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while('0'<=ch&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=getchar();}
    return s*w;
}
long long quick_pow(long long a,long long b)
{
    long long rec=1;
    while(b>0)
    {
        if((b&1)==1)
        {
            rec=rec*a%mod;
        }
        a=a*a%mod;
        b>>=1;
    }
    return rec;
}
long long inv(long long x)
{
    if(x==0)
        return 1;
    return quick_pow(x,mod-2);
}
void deal()
{
    for(int i=1,r;i<=n;i=r+1)
    {
        r=_min(n/(n/i),m/(m/i));
        ans*=quick_pow(sum[r]*sum_inv[i-1]%mod,(n/i)*(m/i)%(mod-1));
        ans%=mod;
    }
    return;
}
signed main()
{
    int T=read();
    f_inv[1]=sum_inv[0]=sum_inv[1]=sum[1]=sum[0]=f[1]=mu[1]=1;
    for(int i=2;i<=N;i++)
    {
        f[i]=(f[i-1]+f[i-2])%mod;
        f_inv[i]=inv(f[i]);
        sum[i]=1;
        if(he[i]==0)
        {
            zhi[++cnt]=i;
            mu[i]=-1;
        }
        for(int j=1;j<=cnt&&zhi[j]*i<=N;j++)
        {
            he[i*zhi[j]]=true;
            if(i%zhi[j]==0)
            {
                mu[i*zhi[j]]=0;
                break;
            }
            else
            {
                mu[i*zhi[j]]=-mu[i];
            }
        }
    }
    for(int i=1;i<=N;i++)
    {
        if(mu[i]==0)
            continue;
        for(int j=1;i*j<=N;j++)
        {
            sum[i*j]=sum[i*j]*(mu[i]==1?f[j]:f_inv[j])%mod;
        }
    }
    for(int i=2;i<=N;i++)
    {
        sum[i]=sum[i]*sum[i-1]%mod;
        sum_inv[i]=inv(sum[i]);
    }
    while(T--)
    {
        ans=1;
        n=read();m=read();
        if(n>m)
            swap(n,m);
        deal();
        printf("%lld\n",((ans+mod)%mod+mod)%mod);
    }
    return 0;
}

 

心得


 太毒瘤了吧,果然信息最难的题是数学题。

补题去了~~~

posted @ 2021-01-31 08:36  HKHbest  阅读(169)  评论(0编辑  收藏  举报
Live2D