zoukankan      html  css  js  c++  java
  • 莫比乌斯反智学习笔记

    莫比乌斯反演

    前言

    莫比乌斯反演是数论中的重要内容。对于一些函数$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;
    }

    心得


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

    补题去了~~~

  • 相关阅读:
    [iOS 主要框架的总结]
    [无线传感器 网络中的节点定位技术]
    [JAVA 多种方式读取文件]
    [IOS swift对比oc]
    [IOS 静态库]
    [U3D 导出Xcode工程包,用Xcode给U3D脚本传递参数]
    [U3D 添加大地、天空,用第一视角看看自己做的世界]
    [U3D 画起重机,绑脚本和控制它运动的基本操作]
    Flutter 国际化适配
    Error:Unable to resolve dependency for ':app@releaseUnitTest/compileClasspath': Coul完美解决
  • 原文地址:https://www.cnblogs.com/HKHbest/p/14348448.html
Copyright © 2011-2022 走看看