q w q qwq qwq机房最后一个学二项式反演的人

众所周知 二项式反演可以表示成
f n = ∑ i = 0 n ( − 1 ) i × C n i × g i ⟺ g n = ∑ i = 0 n ( − 1 ) i × C n i × f i f_n=\sum_{i=0}^n (-1)^i\times C_n^i\times g_i\Longleftrightarrow g_n=\sum_{i=0}^n(-1)^i\times C_n^i \times f_i fn​=i=0∑n​(−1)i×Cni​×gi​⟺gn​=i=0∑n​(−1)i×Cni​×fi​

是一个极其对称的式子,常用表达是
f n = ∑ i = 0 n C n i × g i ⟺ g n = ∑ i = 0 n ( − 1 ) n − i × C n i × f i f_n=\sum_{i=0}^n C_n^i\times g_i\Longleftrightarrow g_n=\sum_{i=0}^n(-1)^{n-i}\times C_n^i \times f_i fn​=i=0∑n​Cni​×gi​⟺gn​=i=0∑n​(−1)n−i×Cni​×fi​

网上有很多很好的证明,比如这个博客,感觉容斥的证明比较形象
我就不写证明了(其实是懒得证

这里只写一些套路的做法和题目

恰好和至多的转换

如果要求 b l a b l a blabla blabla恰好有 k k k个 b l a b l a blabla blabla的时候,有时候会很难算,而求至多有 k k k个 b l a b l a blabla blabla的时候会很好算,最经典的就是错排问题,错排问题好像有递推,但二项式反演也是可以做的

设 f i f_i fi​表示恰好的方案数, g i g_i gi​表示至多的方案数,则有
g n = ∑ i = 0 n C n i × f i g_n=\sum_{i=0}^n C_n^i\times f_i gn​=i=0∑n​Cni​×fi​
根据二项式反演有
f n = ∑ i = 0 n ( − 1 ) n − i × C n i × g i f_n=\sum_{i=0}^n(-1)^{n-i}\times C_n^i\times g_i fn​=i=0∑n​(−1)n−i×Cni​×gi​
然后 g i g_i gi​一般在很短的时间内就可以方便求出,再用 g g g求 f f f就可以得到答案

例题:
hdu1465不容易系列之一

错排问题
设 f i f_i fi​表示恰好有 i i i个错开, g i g_i gi​表示至多有 i i i个错开, g i = i ! g_i=i! gi​=i!,然后套上面那个公式就好了
代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define LL long long
#define N 25
using namespace std;int n;
LL fac[N],f[N],C[N][N];inline void prework(){fac[0]=1;for(int i=1;i<=20;i++) fac[i]=fac[i-1]*i;C[0][0]=1;for(int i=1;i<=20;i++) C[i][0]=1;for(int i=1;i<=20;i++)for(int j=1;j<=i;j++)C[i][j]=C[i-1][j]+C[i-1][j-1];for(int i=1;i<=20;i++)for(int j=0;j<=i;j++)if((i-j)&1) f[i]-=C[i][j]*fac[j];else f[i]+=C[i][j]*fac[j];
}int main(){prework();while(~scanf("%d",&n)){printf("%lld\n",f[n]);}return 0;
}

恰好和至少的转换

同样有时候至少有 k k k个 b l a b l a blabla blabla的要更好求

设 f i f_i fi​表示恰好的方案数, g i g_i gi​表示至少的方案数,则有
g k = ∑ i = k n C i k × f i g_k=\sum_{i=k}^nC_i^k\times f_i gk​=i=k∑n​Cik​×fi​
根据二项式反演有
f k = ∑ i = k n ( − 1 ) i − k × C i k × g i f_k=\sum_{i=k}^n(-1)^{i-k}\times C_i^k\times g_i fk​=i=k∑n​(−1)i−k×Cik​×gi​

例题:
bzoj3622: 已经没有什么好害怕的了
首先因为要求是 a &gt; b a&gt;b a>b多 k k k个,所以 a &gt; b a&gt;b a>b的应该有 n + k 2 \frac{n+k}{2} 2n+k​个(千万别读错题

为了打着舒服设 f i f_i fi​表示至少有 i i i个 a &gt; b a&gt;b a>b的方案数,这个不能直接算,所以考虑 d p dp dp,把 a , b a,b a,b从小到大排序,设 f [ i ] [ j ] f[i][j] f[i][j]表示前 i i i个至少有 j j j个 a &gt; b a&gt;b a>b的方案数,只需要算出来比当前 a [ i ] a[i] a[i]小的 b b b有多少个,再减一下前面用过的,式子就是 f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] × ( c n t [ i ] − j + 1 ) + f [ i − 1 ] [ j ] f[i][j]=f[i-1][j-1]\times (cnt[i]-j+1)+f[i-1][j] f[i][j]=f[i−1][j−1]×(cnt[i]−j+1)+f[i−1][j]

算出来以后再用 f [ n ] [ i ] f[n][i] f[n][i]带入上面的式子里去算最终恰好的答案
注意 f [ n ] [ i ] f[n][i] f[n][i]用的时候还要 × ( n − i ) ! \times (n-i)! ×(n−i)!,因为其他位置是随便放的

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define LL long long
#define N 2005
using namespace std;template<class T>inline void rd(T &x){x=0; short f=1; char c=getchar();while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();x*=f;
}const int mod=1e9+9;
int n,k,C[N][N],f[N][N],a[N],b[N],cnt[N],ans,fac[N];inline void prework(int n){C[0][0]=1;for(int i=1;i<=n;i++) C[i][0]=1;for(int i=1;i<=n;i++)for(int j=1;j<=i;j++)C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;fac[0]=1; for(int i=1;i<=n;i++) fac[i]=1LL*fac[i-1]*i%mod;
}int main(){rd(n); rd(k);if((n+k)&1) return puts("0"),0;prework(n); k=(n+k)>>1;for(int i=1;i<=n;i++) rd(a[i]);for(int i=1;i<=n;i++) rd(b[i]);sort(a+1,a+n+1); sort(b+1,b+n+1);int now=0;for(int i=1;i<=n;i++){while(b[now+1]<a[i] && now<n) now++;cnt[i]=now;}for(int i=0;i<=n;i++) f[i][0]=1;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)f[i][j]=(1LL*f[i-1][j-1]*max((cnt[i]-j+1),0)%mod+1LL*f[i-1][j])%mod;for(int i=k;i<=n;i++){f[n][i]=1LL*f[n][i]*fac[n-i]%mod;if((i-k)&1) (ans+=mod-1LL*C[i][k]*f[n][i]%mod)%=mod;else (ans+=1LL*C[i][k]*f[n][i]%mod)%=mod;}printf("%d\n",ans);return 0;
}

bzoj2839: 集合计数
首先还是设 f i f_i fi​表示恰好交集有 i i i个元素的, g i g_i gi​表示至少的,那么 g i = C n i × ( 2 2 n − i − 1 ) g_i=C_n^i\times (2^{2^{n-i}}-1) gi​=Cni​×(22n−i−1)
这里的含义就是钦定 i i i个必须选,剩下的可以选可以不选的有 2 n − i 2^{n-i} 2n−i个集合,这些集合可选可不选,但不能都不选,就有了上式

再套用上面的公式得出
f k = ∑ i = k n ( − 1 ) i − k × C i k × C n i × ( 2 2 n − i − 1 ) f_k=\sum_{i=k}^n(-1)^{i-k}\times C_i^k\times C_n^i\times (2^{2^{n-i}}-1) fk​=i=k∑n​(−1)i−k×Cik​×Cni​×(22n−i−1)
O ( n ) O(n) O(n)计算即可,注意后面那个 2 2 n − i 2^{2^{n-i}} 22n−i貌似不能直接快速幂因为指数不能 &VeryThinSpace; m o d &VeryThinSpace; p \bmod p modp,要用 2 2 t = ( 2 2 t − 1 ) 2 2^{2^t}=(2^{2^{t-1}})^2 22t=(22t−1)2倒着枚举算

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 1000005
#define LL long long
#define int LL
using namespace std;int n,k,fac[N],inv[N];
LL ans;
const int mod=1000000007;inline int qpow(int x,int k){int ret=1;while(k){if(k&1) ret=1LL*ret*x%mod;x=1LL*x*x%mod; k>>=1;} return ret;
}inline void prework(){fac[0]=1; for(int i=1;i<=n;i++) fac[i]=1LL*fac[i-1]*i%mod;inv[n]=qpow(fac[n],mod-2); for(int i=n;i;i--) inv[i-1]=1LL*inv[i]*i%mod;
}inline LL C(int n,int m){return 1LL*fac[n]*inv[m]%mod*inv[n-m]%mod;}signed main(){scanf("%lld%lld",&n,&k); prework();int bin=2;for(int i=n;i>=k;i--){if((i-k)&1) (ans+=mod-C(i,k)*C(n,i)%mod*(bin-1)%mod)%=mod;else (ans+=C(i,k)*C(n,i)%mod*(bin-1)%mod)%=mod;bin=1LL*bin*bin%mod;}printf("%lld\n",(ans+mod)%mod);return 0;
}

二项式反演(学习笔记)相关推荐

  1. 莫比乌斯反演学习笔记

    背景: 之前不会用MarkdownMarkdownMarkdown,所以坑没有补. 定义: 以下除法默认向下去整. 对于一个形如Fn=∑d∣nfdF_n=\sum_{d|n}f_dFn​=∑d∣n​f ...

  2. 狄利克雷卷积_狄利克雷卷积学习笔记

    蒟蒻我在莫比乌斯反演学习笔记里留下了几个坑,于是开始漫长的填坑路. 狄利克雷卷积学习笔记 前置知识1:数论函数 什么是数论函数呢?数论函数指定义域为正整数,陪域为复数的函数. 以下知识中涉及到的函数大 ...

  3. 二项式反演(广义容斥定理)学习笔记

    背景: 二项式反演又名广义容斥定理. 下次再看题解时要注意了. 解锁新姿势. 说白了就是之前会的姿势太少了. 正题: 说白了就是有这样两条恒等的式子: f n = ∑ i = 0 n ( − 1 ) ...

  4. 莫比乌斯反演专题学习笔记

    莫比乌斯反演专题学习笔记 本文记录一些和莫反有关的内容的笔记 可能存在诸多谬误,阅读时请谨慎分析 若发现文中有谬误,如您愿意,恳请您向我指出,不胜感激! 为什么要学莫比乌斯反演? 解决一类与狄利克雷卷 ...

  5. [学习笔记]多项式与有标号简单图计数

    学了一天的有标号无向图计数真的自闭了- 本篇文章是基于2019WC汪乐平大佬的讲课课件<生成函数,多项式算法与图的计数>编写的. 注意:文中所有生成函数都规定为指数型生成函数(EGF),请 ...

  6. 二项式反演[bzoj3622]已经没有什么好害怕的了

    前言 继续学习容斥的技巧! 题意简介 题面链接 题目大意 给出两个数组a,ba,ba,b 求有多少种对应方式使得有恰好kkk对匹配(i,j)(i,j)(i,j)满足ai>bja_i>b_j ...

  7. 集合计数 二项式反演_对计数数据使用负二项式

    集合计数 二项式反演 The Negative Binomial distribution is a discrete probability distribution that you should ...

  8. 计算机专业常用图论,同等学力申硕计算机专业--数学公式集合(新增学习笔记)...

    组合数学部分: 基础公式: 定义:从n个不同的元素中, 取r个并按次序排列, 称为从n中取r个的一个排列, 全部这样的排列数记为P(n, r). 定义: 从n个不同的元素中, 取r个但是不考虑次序时候 ...

  9. 数学/数论专题-学习笔记:狄利克雷卷积

    数学/数论专题-学习笔记:狄利克雷卷积 1. 前言 2. 一些基础函数 3. 积性函数 4. 狄利克雷卷积 5. 总结 6. 参考资料 1. 前言 狄利克雷卷积,是学习与继续探究 μ\muμ 函数和 ...

最新文章

  1. 当代硕博生常犯错觉大赏:我的idea非常棒,别人肯定想不到!
  2. Tungsten Fabric SDN — Service Chain — Heat Templates
  3. Mac 安装 Eclipse
  4. 以下哪一个不属于python语言的特点-Python语言的特点有哪些
  5. CodeForces - 1363E Tree Shuffling(树上贪心)
  6. 华南农业大学计算机专业学硕20,2020年华南农业大学计算机应用技术考研经验分享...
  7. 不确定下钻数的循环(部门下所属部门 多层下钻)
  8. 使用dbutils对mysql数据库做增删改查的基本操作方法
  9. MySQL无法启动 服务没有报告任何错误
  10. CCNA红头发视频教程全集---91lab
  11. HDU1568 Fibonacci【斐波拉契数列】
  12. class unity 定义类_【Unity学习笔记】C#基础-类(Classes)
  13. 算法笔记_二分查找/斐波那契查找
  14. 前端性能优化—js代码打包 1
  15. Java学习路线图,知识点总结大全图,从入门到精通,你要好好学习Java,千万不能只学习python
  16. 免费的天气API相关编码(中国城市代码检索)
  17. html5库存管理,库存管理的基本方法
  18. 更换光猫的原理与方法
  19. 史上最简单的教程——“21天”自学C语言
  20. Windows创建快捷方式的几种方法你用过哪些?

热门文章

  1. 华为笔试:字符串加密(python版)
  2. C# 将应用程序通过注册表设置开机启动项
  3. qq企鹅图标java源代码_腾讯QQ更换新标识续:看一个企鹅的蜕变之路
  4. Java 里的异常(Exception)详解
  5. opencv——Sobel算子与Scharr算子
  6. 辩论计算机未来不能取代书本的问题,计算机不能取代书本的一辩稿
  7. 惠普服务器dl380安装系统没有f10,惠普Hp DL380 GEN9 UEFI模式安装win2008 r2的方法
  8. linux下进入bios设置u盘启动项,u盘启动g4l_u盘启动快捷键_bios设置u盘启动
  9. 各类通信协议归纳整理(偏硬件)
  10. Jquery参考手册免费下载