• 笔记:莫比乌斯反演


    摘自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
  • 相关阅读:
    微软职位内部推荐-Senior Software Engineer-DUT
    微软职位内部推荐-Senior PM
    面试题:打印蛇形二维数组
    微软职位内部推荐-Principal Software Eng Mgr
    微软职位内部推荐-Senior SDE
    微软职位内部推荐-Senior Software Engineer II-Search
    微软职位内部推荐-Software Engineer II-Search
    分布式锁的实现方式
    Java集合框架实现自定义排序
    Redis的缓存策略和主键失效机制
  • 原文地址:https://www.cnblogs.com/zdsrs060330/p/14093705.html
Copyright © 2020-2023  润新知