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

    前置知识

    以下结论是显然的:

    (1)若( heta)可乘,则

    • ( heta(1)=1)
    • ( heta(n)= hetaleft(p 1^{alpha 1} ight) hetaleft(p 2^{alpha 2} ight) ldots hetaleft(p k^{alpha k} ight))
    • ( heta 1, heta 2) 可乘 (Longrightarrow heta 1 heta 2) 可乘

    (2)(sum_{d mid n}):对n所有的正因子求和
    (left(sum_{d mid n} f(d) ight)left(sum_{d mid n} g(d) ight)=sum_{d_1|n wedge d_2| n} f(d 1) g(d 2))

    (3)【莫比乌斯函数】定义:

    [mu(1)=1, mu(n)=muleft(p 1^{alpha 1} ight) muleft(p 2^{alpha 2} ight) ldots muleft(p k^{alpha k} ight)=left{egin{array}{l}(-1)^{k} ext { 若 } alpha 1=alpha 2=ldots=alpha k=1 \ 0 quad ext { otherwise }end{array} ight. ]

    显然,(mu)为可乘函数

    推论:

    (4)若( heta)可乘,则(psi(n)=sum_{d mid n} heta(d))可乘(下文引用此处的(psi)定义)

    设( (m, n)=1,) 则mn的任一因子可唯一写成d (=d 1 d 2) 其中 (d 1|m, d 2| n),根据结论(2)

    [psi(m n)=sum_{d mid m n} heta(d)=sum_{d_1|mwedge d_2| n} heta(d_1 d_2)=sum_{d_1 mid m} sum_{d_2 mid n} heta(d 1 d 2)=sum_{d 1 mid m} sum_{d 2 mid n} heta(d_1) heta(d_2)= psi(m)*psi(n) ]

    (5)(psi(n)=left(1+ heta(p 1)+ hetaleft(p 1^{2} ight)+ldots ight)left(1+ heta(p 2)+ hetaleft(p 2^{2} ight)+. . ight) ldots)

    该结论由3和可乘函数性质易得。

    (6)若 ( heta) 可乘, (mu heta) 可乘, (sum_{d mid n} mu(d) heta(d)) 也可乘(根据性质4),易得

    [sum_{d mid n} mu(d) heta(d)=(1- heta(p 1))(1- heta(p 2)) ldots .(1- heta(p k)) ]

    特别地,

    [egin{alignat}{1} heta(d) &= 1, sum_{d mid n} mu(d) heta(d)=left{egin{array}{ll}1 & n=1 \ 0 & ext { otherwise }end{array} ight. \ heta(d)&=frac{1}{d}, sum_{d mid n} mu(d) heta(d)=left(1-frac{1}{p 1} ight)left(1-frac{1}{p 2} ight) ldotsend{alignat} ]

    (7)【莫比乌斯反演定理】

    F(n)与f(n)均为数论函数

    [若满足F(n)=sum_{d mid n} f(d),则有f(n)=sum_{d mid n} mu(d) Fleft(frac{n}{d} ight)(形式一) \若满足F(n)=sum_{n mid d} f(d),则有f(n)=sum_{n mid d} mu(frac{d}{n}) Fleft(d ight) (形式二) ]

    证明:

    (left(left{egin{array}{l}d mid n \ d 1 mid frac{n}{d}end{array} Leftrightarrowleft{egin{array}{l}d mid frac{n}{d 1} \ d 1 mid nend{array} ight) ight. ight.)

    [egin{alignat}{1}sum_{d mid n} mu(d) Fleft(frac{n}{d} ight)&=sum_{d mid n} mu(d) sum_{d_1 mid frac{n}{d}} f(d 1) \ &=sum_{d mid frac{n}{d 1}} mu(d) sum_{d 1 mid n} f(d 1) \&=sum_{d 1 mid n} f(d 1) sum_{d mid frac{n}{d 1}} mu(d)end{alignat} ]

    根据性质(6)中( heta=1)的情况,只有n=1时函数能取到1,因此只有(frac{n}{d_1}=1)时该项对答案有贡献,即(d_1=n),因此(sum_{d 1 mid n} f(d 1) sum_{d mid frac{n}{d 1}} mu(d)=f(n)),形式一证毕

    例题

    POJ3904 Sky Code

    题意:

    给出n个数,问有多少4元组的gcd为1

    思路:

    直接求很困难,需要容斥,考虑进行转换:

    设F(n):有多少四元组满足gcd为n的整数倍

    f(n):有多少四元组满足gcd为n

    F与f满足第二类反演条件(F(n)=sum_{n mid d} f(d))

    F(n)很好求,只要将包含因数n的数个数num预处理出来即可,(F(n)=C(num,4))

    答案即为f(1),可以通过反演第二种形式转换为求F(n),即

    [f(1)=mu(1) F(1)+mu(2) F(2)+ldots ldots+mu(max n) F(max n)​ ]

    代码:

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    const int maxn=1e4+5;
    const int maxp=1e4+5;
    bool isPrime[maxn];
    int Prime[maxp], primecnt = 0;
    int mu[maxn];
    void GetPrime(int n){//筛到n
    	memset(isPrime, 1, sizeof(isPrime));
    	isPrime[1] = 0;//1不是素数
    	mu[1]=1;
    	for(int i = 2; i <= n; i++){
    		if(isPrime[i])//没筛掉
    			Prime[++primecnt] = i, mu[i]=-1; //i成为下一个素数
    		for(int j = 1; j <= primecnt && i*Prime[j] <= n; j++) {
    			isPrime[i*Prime[j]] = 0;
    			if(i % Prime[j] == 0){//i中也含有Prime[j]这个因子
    			    mu[i*Prime[j]]=0;
    				break;
    			}
                else{
                    mu[i*Prime[j]]=-mu[i];
                }
    		}
    	}
    }
    ll Cn4(ll n){
        if(n<=3){
            return 0;
        }
        else{
            return n*(n-1)*(n-2)*(n-3)/24;
        }
    }
    int a[maxn];
    int tot[maxn];
    void init(int n){
        memset(tot,0,sizeof tot);
    }
    int main () {
        const int N=10000;
        GetPrime(N);
        int n;
        while(~scanf("%d",&n)){
            init(n);
            for(int i=1;i<=n;i++){
                scanf("%d",&a[i]);
            }
            for(int i=1;i<=n;i++){
                int right=sqrt(a[i]);
                for(int j=1;j<=right;j++){
                    if(a[i]%j==0){
                        tot[j]++;
                        tot[a[i]/j]++;
                    }
                }
                if(right*right==a[i]){//多统计了一次
                    tot[right]--;
                }
            }
            ll ans=0;
            for(int i=1;i<=maxn-1;i++){
                ans+=(ll)mu[i]*Cn4(tot[i]);
            }
            printf("%lld
    ",ans);
        }
    }
    

    参考与引用:

    https://blog.csdn.net/tomandjake_/article/details/81083051

    https://blog.csdn.net/tomandjake_/article/details/81083703

  • 相关阅读:
    我爱java系列之---【微服务间的认证—Feign拦截器】
    我爱java系列之---【设置权限的三种解决方案】
    581. Shortest Unsorted Continuous Subarray
    129. Sum Root to Leaf Numbers
    513. Find Bottom Left Tree Value
    515. Find Largest Value in Each Tree Row
    155. Min Stack max stack Maxpop O(1) 操作
    painting house
    Minimum Adjustment Cost
    k Sum
  • 原文地址:https://www.cnblogs.com/ucprer/p/13494717.html
Copyright © 2011-2022 走看看