模板:组合数学

组合数学

组合数取模

为方便,记 C ( n , m ) = C n m = ( n m ) C(n,m)=C_n^m=\binom{n}{m} C(n,m)=Cnm=(mn)

struct Factorial//预处理阶乘及对应的逆元
{
	vector fac,ifac;
	ll M;
	Factorial(int N,ll M):fac(N,1),ifac(N,1),M(M)
	{
		for(int i=2; i

组合数lcm

( n + 1 ) l c m ( C ( n , 0 ) , C ( n , 1 ) , … , C ( n , k ) ) = l c m ( n + 1 , n , n − 1 , n − 2 , … , n − k + 1 ) (n + 1)lcm(C(n,0),C(n,1),\ldots,C(n,k))=lcm(n+1,n,n−1,n−2,\ldots,n−k+1) (n+1)lcm(C(n,0),C(n,1),,C(n,k))=lcm(n+1,n,n1,n2,,nk+1)

区间lcm的维护

对于一个数,将其分解质因数,若有因子 p k p^k pk,那么拆分出k个数 p 1 , p 2 , … , p k p^1,p^2,\ldots,p^k p1,p2,,pk,权值都为p,那么区间 [ l , r ] [l,r] [l,r]内所有数的lcm的答案=所有在该区间中出现过的数的权值之积,可持久化线段树维护之。

Stirling数

第一类斯特林数

第一类斯特林数 S ( p , k ) S(p,k) S(p,k)的一个的组合学解释是:将p个物体排成k个非空循环排列的方法数。
递推公式: S ( p , k ) = ( p − 1 ) S ( p − 1 , k ) + S ( p − 1 , k − 1 ) , 1 ≤ k ≤ p − 1 ; S ( p , 0 ) = 0 , p ≥ 1 ; S ( p , p ) = 1 , p ≥ 0 S(p,k) = (p−1)S(p−1,k)+S(p−1,k−1),1\leq k\leq p−1;S(p,0) = 0,p\ge1;S(p,p) = 1,p\ge0 S(p,k)=(p1)S(p1,k)+S(p1,k1),1kp1;S(p,0)=0,p1;S(p,p)=1,p0

第二类斯特林数

第二类斯特林数 S ( p , k ) S(p,k) S(p,k)的一个的组合学解释是:将p个物体划分成k个非空不可辨别的(可以理解为盒子没有编号)集合的方法数。
递推公式: S ( p , k ) = k S ( p − 1 , k ) + S ( p − 1 , k − 1 ) , 1 ≤ k ≤ p − 1 ; S ( p , 0 ) = 0 , p ≥ 1 ; S ( p , p ) = 1 , p ≥ 0 S(p,k) = kS(p−1,k) + S(p−1,k−1),1\leq k\leq p−1;S(p,0) = 0,p\ge 1;S(p,p) = 1,p\ge0 S(p,k)=kS(p1,k)+S(p1,k1),1kp1;S(p,0)=0,p1;S(p,p)=1,p0
卷积形式: S ( n , m ) = 1 m ! ∑ k = 0 m ( − 1 ) k C ( m , k ) ( m − k ) n = ∑ k = 0 m ( − 1 ) k k ! ( m − k ) n ( m − k ) ! S(n,m)=\frac{1}{m!}\sum_{k=0}^m (-1)^kC(m,k)(m-k)^n=\sum_{k=0}^m\frac{(-1)^k}{k!}\frac{(m-k)^n}{(m-k)!} S(n,m)=m!1k=0m(1)kC(m,k)(mk)n=k=0mk!(1)k(mk)!(mk)n
同时有转化: x k = ∑ i = 1 k i ! C ( x , i ) S ( k , i ) x^k=\sum_{i=1}^ki!C(x,i)S(k,i) xk=i=1ki!C(x,i)S(k,i)

斯特林近似公式

n ! ≈ 2 π n ( n e ) n n!\approx\sqrt{2πn}(\frac{n}{e})^n n!2πn (en)n

小球入盒问题

k 个球 m个盒子 空盒子 方案数
各不相同 各不相同 允许 m k m^k mk
各不相同 各不相同 m ! S t i r l i n g 2 ( k , m ) m!Stirling2(k,m) m!Stirling2(k,m)
各不相同 完全相同 允许 ∑ i = 1 m S t i r l i n g 2 ( k , i ) \sum_{i=1}^mStirling2(k,i) i=1mStirling2(k,i)
各不相同 完全相同 S t i r l i n g 2 ( k , m ) Stirling2(k,m) Stirling2(k,m)
完全相同 各不相同 允许 C ( m + k − 1 , k ) C(m+k−1,k) C(m+k1,k)
完全相同 各不相同 C ( k − 1 , m − 1 ) C(k−1,m−1) C(k1,m1)
完全相同 完全相同 允许 1 ( 1 − x ) ( 1 − x 2 ) . . . ( 1 − x m ) 的 x k 项 的 系 数 \frac{1}{(1−x)(1−x^2)...(1−x^m)}的x^k项的系数 (1x)(1x2)...(1xm)1xk
完全相同 完全相同 x m ( 1 − x ) ( 1 − x 2 ) . . . ( 1 − x m ) 的 x k 项 的 系 数 \frac{x^m}{(1−x)(1−x^2)...(1−x^m)}的x^k项的系数 (1x)(1x2)...(1xm)xmxk

置换

struct Permutation:vector
{
	Permutation(int n=0):vector(n) {}
	friend Permutation operator*(const Permutation &f,const Permutation &g)
	{
		Permutation ans(f.size());
		for(int i=0; i > cycle(const Permutation &f)
	{
		vector vis(f.size(),0);
		vector > ans;
		for(int i=0; i());
				for(int j=i; !vis[j]; j=f[j])
				{
					vis[j]=1;
					ans.back().push_back(j);
				}
			}
		return ans;
	}
};

生成下一字典序

生成排列

对给定的排列 a 1 a 2 … a n a_1a_2\ldots a_n a1a2an,找到 a j a_j aj使得 a j < a j + 1 , a j + 1 > a j + 2 > … > a n a_j<a_{j+1},a_{j+1}>a_{j+2}>\ldots>a_n aj<aj+1,aj+1>aj+2>>an即这列数中最后一个相邻递增数对,然后把 a j + 1 , a j + 2 , … , a n a_{j+1},a_{j+2},\ldots,a_n aj+1,aj+2,,an中大于 a j a_j aj的最小数放到位置j,然后 a j … a n a_j\ldots a_n ajan中剩余的数从小到大排序放到 [ j + 1 , n ] [j+1,n] [j+1,n]中。

bool nextPermutation(ll *b,ll *e)//标准库有这个函数next_permutation
{
	ll *i=e-1,*j=e-2;
	while(j>=b&&*j>=*(j+1))--j;
	if(j

生成组合

//待填坑

位运算应用

生成所有非空子集

枚举i的非空子集j。

for(j=i; j; j=i&j−1) {}

gcc内置位运算

这些函数都有相应的usigned longusigned long long版本,只需要在函数名后面加上lll就可以了,比如__builtin_clzll.

int __builtin_clz(unsigned int x);//求前缀0的个数
int __builtin_ctz(unsigned int x);//求后缀0的个数
int __builtin_ffs(unsigned int x);//x的二进制末尾最后一个1的位置,从1开始
int __builtin_popcount(unsigned int x);//x二进制中1的个数,相当于bitset::count()
int __builtin_parity(unsigned int x);//判断x的二进制中1的个数的奇(1)偶(0)性

二项式反演

f ( n ) = ∑ k = 0 n C ( n , k ) g ( k ) , g ( n ) = ∑ k = 0 n ( − 1 ) n − k C ( n , k ) f ( k ) f(n)=\sum_{k=0}^nC(n,k)g(k),g(n)=\sum_{k=0}^n(−1)^{n−k}C(n,k)f(k) f(n)=k=0nC(n,k)g(k),g(n)=k=0n(1)nkC(n,k)f(k)

第k小期望

f ( n , k ) f(n,k) f(n,k) 表示有n个变量,和为1,第k小的期望。
f ( n , k ) = 1 n 2 + ( 1 − 1 n ) f ( n − 1 , k − 1 ) , f ( n , 0 ) = 0 f(n,k)=\frac{1}{n^2}+(1-\frac{1}{n})f(n-1,k-1),f(n,0)=0 f(n,k)=n21+(1n1)f(n1,k1),f(n,0)=0

错排数

考虑一个有n个元素的排列,若一个排列中所有的元素都不在自己原来的位置上,那么这样的排列就称为原排列的一个错排。
n个元素的错排数 D n D_n Dn满足递推公式: D 1 = 0 , D 2 = 1 , D n = ( n − 1 ) ( D n − 2 + D n − 1 ) D_1=0,D_2=1,D_n=(n−1)(D_{n−2}+D_{n−1}) D1=0,D2=1,Dn=(n1)(Dn2+Dn1)
通项: D ( n ) = n ! [ ( − 1 ) 2 2 ! + … + ( − 1 ) n − 1 ( n − 1 ) ! + ( − 1 ) n n ! ] = ⌊ n ! e + 1 2 ⌋ D(n)=n![\frac{(-1)^2}{2!}+\ldots+\frac{(-1)^{n-1}}{(n-1)!}+\frac{(-1)^n}{n!}]=\lfloor\frac{n!}{e}+\frac{1}{2}\rfloor D(n)=n![2!(1)2++(n1)!(1)n1+n!(1)n]=en!+21

Bonuli数

B n = − 1 C ( n + 1 , n ) ( C ( n + 1 , 0 ) B 0 + C ( n + 1 , 1 ) B 1 + … + C ( n + 1 , n − 1 ) B n − 1 ) = − 1 n + 1 ( C ( n + 1 , 0 ) B 0 + C ( n + 1 , 1 ) B 1 + … + C ( n + 1 , n − 1 ) B n − 1 ) B_n = -\frac{1}{C(n+1,n)}(C(n+1,0)B_0+C(n+1,1)B_1+\ldots+C(n+1,n-1)B_{n-1})=-\frac{1}{n+1}(C(n+1,0)B_0+C(n+1,1)B_1+\ldots+C(n+1,n-1)B_{n-1}) Bn=C(n+1,n)1(C(n+1,0)B0+C(n+1,1)B1++C(n+1,n1)Bn1)=n+11(C(n+1,0)B0+C(n+1,1)B1++C(n+1,n1)Bn1)
可用于计算任意正整数次数的幂和: ∑ i = 1 n i k = 1 k + 1 ∑ j = 0 k C ( k + 1 , j ) B j n k + 1 − j \sum_{i=1}^ni^k=\frac{1}{k+1}\sum_{j=0}^kC(k+1,j)B_jn^{k+1-j} i=1nik=k+11j=0kC(k+1,j)Bjnk+1j

struct Bonuli:Factorial
{
	vector b;
	Bonuli(int N,ll M):Factorial(N,M),b(N,0)
	{
		for(int i=b[0]=1; i

Catalan数

h 1 = 1 , h n = 4 n − 2 n + 1 h n − 1 = C ( 2 n , n ) n + 1 = C ( 2 n , n ) − C ( 2 n , n − 1 ) h_1 = 1,h_n =\frac{4n−2}{n+1}h_{n−1} =\frac{C(2n,n)}{ n+1 }= C(2n,n)−C(2n,n−1) h1=1,hn=n+14n2hn1=n+1C(2n,n)=C(2n,n)C(2n,n1)
在一个格点阵列中,从 ( 0 , 0 ) (0,0) (0,0)点走到 ( n , m ) (n,m) (n,m)点且不经过对角线 x = y x=y x=y的方法数:$ C(n + m−1,m)−C(n + m−1,m−1),x > y;C(n + m,m)−C(n + m,m−1),x\ge y$。

Bell数

把n个带标号的物品划分为若干不相交集合的方案数称为贝尔数,其递推公式: B n = ∑ i = 0 N − 1 C n − 1 i B i B_n=\sum_{i=0}^{N-1}C_{n-1}^iB_i Bn=i=0N1Cn1iBi
前几项贝尔数: 1 , 2 , 5 , 15 , 52 , 203 , 877 , 4140 , 21147 , 115975 , 678570 , 4213597 , 27644437 , 190899322 , 1382958545 , … 1,2,5,15,52,203,877,4140,21147,115975,678570,4213597,27644437,190899322,1382958545,\ldots 1,2,5,15,52,203,877,4140,21147,115975,678570,4213597,27644437,190899322,1382958545,
下为 O ( P 2 log ⁡ P ) O(P^2\log P) O(P2logP) B n B_n Bn对P取模。

struct Bell {
	static const int P=999999598,N=7284;
	int a[4],f[N],s[2][N],i,j,x;
	Bell() {
		a[0]=2,a[1]=13,a[2]=5281,a[3]=7283;//P的质因数分解
		f[0]=f[1]=s[0][0]=1,s[0][1]=2;
		for(i=2,x=1; i

等价类容斥

考虑容斥,Bell§枚举所有等价情况。对于一种情况,强制了一个等价类里面的数都要相同,其它的可以相同也可以不同。
容斥系数为: ( − 1 ) p − 等 价 类 个 数 ( 每 个 等 价 类 大 小 − 1 ) ! 之 积 (−1)^{p−等价类个数}(每个等价类大小−1)!之积 (1)p(1)!

Grey码

格雷序列第i个是i^(i>>1)。长为n的01序列共 2 n 2^n 2n个,下标从 0 … 2 n − 1 0\ldots 2^n-1 02n1

扩展Cayley公式

对于n个点,m个连通块的图,假设每个连通块有a[i]个点,那么用s−1条边把它连通的方案数为 n s − 2 a [ 1 ] a [ 2 ] . . . a [ m ] n^{s−2}a[1]a[2]...a[m] ns2a[1]a[2]...a[m]

超立方体

n维超立方体有 2 n − i C ( n , i ) 2^{n−i}C(n,i) 2niC(n,i) 个i维元素。

有根树森林

固定k个点作为根的n个点的带标号有根树森林的方案数是 n n − k − 1 k n^{n−k−1}k nnk1k

你可能感兴趣的:(acm,模板)