zoukankan      html  css  js  c++  java
  • [容斥原理与莫比乌斯反演][学习笔记]

    容斥原理 与 莫比乌斯反演

    今天(2.23.2017)翻了一下《组合数学》前6章,发现我之前一定是学了假的莫比乌斯反演,于是来新写一篇



    # 容斥原理

    定理

    集合(S)中不具有性质(P_i:1le i le m)的元素个数:
    (A_i)为具有性质(P_i)的集合

    ( |S| - sum{|A_i|} + sum{A_i igcap A_j} -sum{A_i igcap A_j igcap A_k}+...+ (-1)^msum{A_1 igcap A_2 igcap ... igcap A_m} )



    项数:$ inom{m}{0} + inom{m}{1} + ... + inom{m}{m} = 2^m$


    (Proof.)
    (1.) 没有任何一条性质的元素贡献为(1)
    (2.)(n)条性质的元素,在(n)个集合(A_i)中出现,贡献为(inom{n}{0} - inom{n}{1} + inom{n}{2} + ... + (-1)^ninom{n}{n} = 0)


    关于第二条的证明:
    根据二项式定理,((1-1)^n =0 : n eq 0)
    或者考虑前(n-1)个元素都可以选或不选,最后一个元素为了保证选的元素个数的奇偶性只有一种选择,所以奇数个元素的子集数量和偶数个元素的子集数量相等

    实质

    [sumlimits_{i=0}^{n}(-1)^iinom{n}{i} = [n=0] ]

    也就是上面的证明过程



    错排

    满足(i_j eq j)的排列数

    [D_n = n!sumlimits_{i=0}^{n}frac{(-1)^i}{i!} ]

    (inom{n}{i}(n-i)! = frac{n!}{i!}) 就是(ge i)个位置不是错排的方案数,应用容斥原理即可

    还有一个递推关系
    (D_n = nD_{n-1} + (-1)^n)


    总结

    在统计一类问题时,应用容斥原理可以有效的弱化限制条件
    有一种统计恰好k个的问题,限制很强,通常弱化为先拿出k个,剩下的任意
    这时候容斥的形式通常是

    [= ge k个 - ge k+1个 + ge k+2个 ... ]

    这时候我们在统计(ge j:k le j le n)时,如果依靠了枚举哪j个或者类似的DP,可能会过多的统计,比如一个(k+i)个的方案在这时候会被考虑(inom{k+i}{k})次,所以需要乘上一个组合数系数(inom{k+i}{k})

    有的问题是恰好没有之类的,这时候(inom{i}{0}=1)所以不用考虑这个东西;同理,恰好n个也不用考虑。

    update 2017.5.3:貌似这个东西也不是这么回事儿...感觉还与二项式反演有关...还是具体问题具体分析吧


    **update 2017.5.15**

    今天闲来无事证明了一下,这玩意应该是普遍成立的!

    我们考虑一个恰好(x:x ge k)个的方案被统计的次数:

    [egin{align} &= sum_{i=k}^x (-1)^{i-k}inom{i}{k} inom{x}{i} \ &= inom{x}{k} sum_{i=k}^x (-1)^{i-k} inom{x-k}{x-i}\ &= inom{x}{k} sum_{j=0}^{x-k} inom{x-k}{j} \ &= [x==k] end{align} ]

    哈哈O(∩_∩)O


    莫比乌斯反演 Mobius Inversion

    说明

    容斥原理是莫比乌斯反演在有限偏序集上的一个实例
    莫比乌斯反演应用在一类二变量函数,偏序关系到实数的映射
    《组合数学》上讨论了好多任意有限偏序集的莫比乌斯反演,还有偏序集的直积,我已经看蒙了
    所以直接说莫比乌斯反演在数论上的经典形式吧,反正不是整除关系也不会考



    积性函数

    定义

    定义域为正整数集的函称为数论函数

    满足(f(ab) = f(a)f(b) : gcd(a,b) =1)的数论函数称为积性函数

    完全积性函数对ab没有互质限制


    积性函数:(varphi(n), mu(n))

    完全积性函数:

    • 单位函数(epsilon(n)=[n=1]),

    • 恒等函数(id(n)=n)

    • 常函数(1(n)=1)


    狄利克雷卷积

    [(f*g)(n) = sumlimits_{d|n}f(d)g(frac{n}{d}) ]

    满足交换律结合律对加法的分配律,单位元 (epsilon)


    ###性质 1. 积性函数的**点积**和**狄利克雷卷积**也是积性函数 2. 一个函数的约数和可以卷上$1$,如约数个数$d(n)=(1*1)(n)$,约数和 $sigma(n) = (1*id)(n)$

    计算

    1. 可以(O(nlogn))预处理,无脑枚举所有数的倍数
    2. 线性筛
    • i=1, i是质数和i%p[j]!=0的情况很好求
    • 对于i%p[j] == 0,可以通过分析增加一个最小质因子后的变化,或者直接考虑(f(p^k))怎么求,反正积性函数不同质因子都是互质乘起来就行了不影响
    • 也可以筛出最小质因子的次数,分解成(f(n) = f(p^k) f(frac{n}{p^k})),对于(f(p^k))考虑如何计算,带有约数和的可以考虑展开
    • 一些非积性函数也可以通过分析函数的性质也可以用线性筛来求
      例:欧拉函数可以直接根据公式得到如何处理 (varphi(n) = nprodfrac{p_i-1}{p_i} = prod{(p_i-1)*p_i^{e_i-1}})
    void sieve() {
    	varphi[1] = 1;
    	for(int i=2; i<=n; i++) {
    		if(!notp[i]) p[++p[0]] = i, varphi[i] = i-1;
    		for(int j=1; j<=p[0] && i*p[j]<=n; j++) {
    			notp[i*p[j]] = 1;
    			if(i%p[j] == 0) {
    				varphi[i*p[j]] = varphi[i] * p[j];
    				break;
    			}
    			varphi[i*p[j]] = varphi[i] * (p[j]-1);
    		}
    	}
    	for(int i=1; i<=n; i++) varphi[i] += varphi[i-1];
    }
    



    ##莫比乌斯函数 $$ mu(1) = 1\ mu(n) = (-1)^i quad n 是i个质数之积 \ mu(n) = 0 quad p^2 | n, p > 1 $$

    [ mu * 1 = epsilon, 即 sumlimits_{d|n}mu(d) = [n=1]$$。 </br> $Proof. $设$n$有$k$种质因子, ]

    sumlimits_{d|n}mu(d) = sum_{i=0}^{k}(-1)^iinom{k}{i}

    [和上面的容斥原理证明类似,应用二项式定理 </br> ## 欧拉函数 ]

    varphi(n) = sum_{i=1}^n [(n,i)=1]
    varphi(n) = prod p^{c-1}(p-1)

    [ </br> 1. $$ varphi * 1 = id 即 n = sumlimits_{d|n}varphi(d) , 反演后 mu * id = varphi ]

    (Proof.) 考虑列出所有分子(frac{i}{n})一共(n)

    1. [sum_{i=1}^n [(n,i)=1]*i = frac{[n=1] + n*varphi(n)}{2} ]

      (Proof.) ((n,i)=(n, n-i)),除了1和2 互质成对出现,和为n


    莫比乌斯反演

    [g(n) = sum_{d|n}f(d) \ f(n) = sum_{d|n}mu(d)g(frac{n}{d}) ]

    (g = f*1 ightarrow f = g * mu)


    (Proof.)
    两边都卷上(mu * 1)
    其他证明方法还有很多,我写这个是因为这个短


    另一种形式

    [g(n) = sum_{n|d}f(n) \ f(n) = sum_{n|d}mu(d)g(frac{d}{n}) ]


    ***

    应用

    感觉还是直接使用这个式子代换比较简单,构造函数再进行反演好像并不好想

    [sumlimits_{d|n}mu(d) = [n=1] ]

    有一些常见技巧:

    • 枚举gcd取值
    • 交换枚举倍数与约数
    • 用莫比乌斯函数求和替换
    • 改写求和指标
    • 最后通常需要得到一个可以整除分块的形式,处理一个函数的前缀和后可以在根号复杂度内解决一次询问

    一般的题目推导起来挺套路的,通常都是枚举两个变量求一个带着gcd的东西(有的题目需要你自己把式子变形把gcd放进去),套路推♂倒之后都变成了整除分块,然后重点就在如何通过线性筛求函数了

    栗子

    [egin{align*} sumlimits_{i=1}^n sum_{j=1}^m gcd(i,j) &= sum_{d=1}^n d sum_{i=1}^n sum_{j=1}^m [gcd(i,j)=d] \ 先枚举d再枚举倍数,出现[=1]的形式 \ &=sum_{d=1}^n d sum_{i=1}^{frac{n}{d}} sum_{j=1}^{frac{m}{d}} [gcd(i,j)=1] \ 用sumlimits_{e|n}mu(e) = [n=1]替换 ,先枚举e再枚举倍数\ &=sum_{d=1}^n dsum_{e=1}^n mu(e) frac{n}{de} frac{m}{de} \ 改写求和指标,令D = de \ &= sum_{D=1}^n sum_{d|D} dmu(frac{D}{d}) frac{n}{D} frac{m}{D}\ 发现最后就是 id * mu = varphi \ &= sum_{D=1}^n varphi(D) frac{n}{D} frac{m}{D}\ end{align*} ]

    代码

    int notp[N], p[N];ll varphi[N];
    void sieve(int n) {
        varphi[1]  1;
        for(in i=2; i<=n; i++) {
            if(!notp[i]) p[++p[0]] = i, varphi[i] = i-1;
            for(int j=1; j<=p[0] && i*p[j]<=n; j++) {
                notp[i*p[j]] = 1;
                if(i%p[j] == 0) {varphi[i*p[j]] = varphi[i]*p[j]; break;}
                varphi[i*p[j]] = varphi[i]*(p[j]-1);
            }
        }
        for(int i=1; i<=n; i++) varphi[i] += varphi[i-1];
    }
    ll cal(int n, int m) {
        ll ans=0; int r;
        for(int i=1; i<=n; i=r+1) {
            r = min(n/(n/i), m/(m/i));
            ans += (varphi[r] - varphi[i-1]) * (n/i) * (m/i);
        }
        return ans;
    }
    
  • 相关阅读:
    http请求user_agent字段解析
    搭建docker registry私有镜像仓库
    k8s遇见的问题
    nginx相关知识
    iOS学习笔记(8)——GCD初探
    iOS学习笔记(7)——解析json中的中文
    SAE实践——创建简单留言板
    SAE实践——创建新应用开启MySQL服务
    SAE实践——用SVN命令行同步/提交代码
    PHP错误——Allowed memory size of 134217728 bytes exhausted (tried to allocate 32 bytes)
  • 原文地址:https://www.cnblogs.com/candy99/p/mobius.html
Copyright © 2011-2022 走看看