CC BY 4.0 (除特别声明或转载文章外)
如果这篇博客帮助到你,可以请我喝一杯咖啡~
组合数取模
为方便,记$C(n,m)=C_n^m=\binom{n}{m}$。
struct Factorial : Mod
{
vector<ll> fac, ifac;
Factorial(int N, ll M) : fac(N, 1), ifac(N, 1), Mod(M)
{
for (int i = 2; i < N; ++i)
fac[i] = mul(fac[i - 1], i), ifac[i] = mul(M - M / i, ifac[M % i]);
for (int i = 2; i < N; ++i)
ifac[i] = mul(ifac[i], ifac[i - 1]);
}
ll c(int n, int m) { return mul(mul(fac[n], ifac[m]), ifac[n - m]); }
ll lucas(ll n, ll m) //卢卡斯定理求C(n,m)%M,适用于模数M小于N的情况,或者m较小的时候也可以暴力求
{
if (!m)
return 1;
if (n < m || n % M < m % M)
return 0;
if (n < M && m < M)
return c(n, m);
return mul(lucas(n / M, m / M), lucas(n % M, m % M));
}
};
组合数 LCM
$(n + 1)lcm(C(n,0),C(n,1),\dots,C(n,k))=lcm(n+1,n,n−1,n−2,\dots,n−k+1)$
区间 lcm 的维护:对于一个数,将其分解质因数,若有因子$p^k$,那么拆分出 k 个数 $p^1,p^2,\dots,p^k$,权值都为 p,那么区间$[l,r]$内所有数的 lcm 的答案=所有在该区间中出现过的数的权值之积,可持久化线段树维护之。
Stirling 数
第一类斯特林数
第一类斯特林数$S(p,k)$的一个的组合学解释是:将 p 个物体排成 k 个非空循环排列的方法数。
递推公式:$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)$的一个的组合学解释是:将 p 个物体划分成 k 个非空不可辨别的(可以理解为盒子没有编号)集合的方法数。
递推公式:$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(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)!}$
同时有转化:$x^k=\sum_{i=1}^ki!C(x,i)S(k,i)$
斯特林近似公式
$n!\approx\sqrt{2\pi n}(\frac{n}{e})^n$
小球入盒模型通解
k 个球 | m 个盒子 | 空盒子 | 方案数 |
---|---|---|---|
各不相同 | 各不相同 | 允许 | $m^k$ |
各不相同 | 各不相同 | 无 | $m!Stirling2(k,m)$ |
各不相同 | 完全相同 | 允许 | $\sum_{i=1}^mStirling2(k,i)$ |
各不相同 | 完全相同 | 无 | $Stirling2(k,m)$ |
完全相同 | 各不相同 | 允许 | $C(m+k−1,k)$ |
完全相同 | 各不相同 | 无 | $C(k−1,m−1)$ |
完全相同 | 完全相同 | 允许 | $\frac{1}{(1−x)(1−x^2)…(1−x^m)}的x^k项的系数$ |
完全相同 | 完全相同 | 无 | $\frac{x^m}{(1−x)(1−x^2)…(1−x^m)}的x^k项的系数$ |
置换
struct Permutation : vector<int>
{
Permutation(int n = 0) : vector<int>(n) {}
friend Permutation operator*(const Permutation &f, const Permutation &g)
{
Permutation ans(f.size());
for (int i = 0; i < f.size(); ++i)
ans[i] = g[f[i]];
return ans;
}
friend Permutation inv(const Permutation &f)
{
Permutation ans(f.size());
for (int i = 0; i < f.size(); ++i)
ans[f[i]] = i;
return ans;
}
friend vector<vector<int>> cycle(const Permutation &f)
{
vector<int> vis(f.size(), 0);
vector<vector<int>> ans;
for (int i = 0; i < f.size(); ++i)
if (!vis[i])
{
ans.push_back(vector<int>());
for (int j = i; !vis[j]; j = f[j])
vis[j] = 1, ans.back().push_back(j);
}
return ans;
}
};
生成字典序
下一排列
对给定的排列$a_1a_2\dots a_n$,找到$a_j$使得$a_j<a_{j+1},a_{j+1}>a_{j+2}>\dots>a_n$即这列数中最后一个相邻递增数对,然后把$a_{j+1},a_{j+2},\dots,a_n$中大于$a_j$的最小数放到位置 j,然后$a_j\dots a_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 < b)
return 0;
while (*i <= *j)
--i;
return swap(*i, *j), reverse(j + 1, e), 1;
}
二项式反演
$f(n)=\sum_{k=0}^nC(n,k)g(k),g(n)=\sum_{k=0}^n(−1)^{n−k}C(n,k)f(k)$
第 k 小期望
$f(n,k)$表示有 n 个变量,和为 1,第 k 小的期望。
$f(n,k)=\frac{1}{n^2}+(1-\frac{1}{n})f(n-1,k-1),f(n,0)=0$
错排数
考虑一个有 n 个元素的排列,若一个排列中所有的元素都不在自己原来的位置上,那么这样的排列就称为原排 列的一个错排。
n 个元素的错排数$D_n$满足递推公式:$D_1=0,D_2=1,D_n=(n−1)(D_{n−2}+D_{n−1})$
通项:$D(n)=n![\frac{(-1)^2}{2!}+\dots+\frac{(-1)^{n-1} }{(n-1)!}+\frac{(-1)^n}{n!}]=\lfloor\frac{n!}{e}+\frac{1}{2}\rfloor$
Bonuli 数
$B_n = -\frac{1}{C(n+1,n)}(C(n+1,0)B_0+C(n+1,1)B_1+\dots+C(n+1,n-1)B_{n-1})=-\frac{1}{n+1}(C(n+1,0)B_0+C(n+1,1)B_1+\dots+C(n+1,n-1)B_{n-1})$
可用于计算任意正整数次数的幂和:$\sum_{i=1}^ni^k=\frac{1}{k+1}\sum_{j=0}^kC(k+1,j)B_jn^{k+1-j}$
struct Bonuli : Factorial
{
vector<ll> b;
Bonuli(int N, ll M) : Factorial(N, M), b(N, 0)
{
for (int i = b[0] = 1; i < N; ++i)
{
for (int j = 0; j < i; ++j)
b[i] = qadd(b[i], mul(b[j], c(i + 1, j)));
b[i] = qadd(M, -mul(b[i], mul(fac[i], ifac[i + 1])));
}
}
ll ask(ll n, int k)
{
ll r = 0, w = 1, u = add(n, 1);
for (int i = 1; i <= k + 1; ++i)
r = qadd(r, mul(mul(b[k + 1 - i], c(k + 1, i)), w = mul(w, u)));
return mul(r, mul(fac[k], ifac[k + 1]));
}
};
Catalan 数
$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)$。
在一个格点阵列中,从$(0,0)$点走到$(n,m)$点且不经过对角线$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$。
常见的 Catalan 数:括号序的个数、凸多边形三角剖分的方案数等。
Bell 数
把 n 个带标号的物品划分为若干不相交集合的方案数称为贝尔数,其递推公式:$B_n=\sum_{i=0}^{N-1}C_{n-1}^iB_i$
前几项贝尔数:
1,2,5,15,52,203,877,4140,21147,115975,678570,4213597,27644437,190899322,1382958545,...
等价类容斥
考虑容斥,Bell(p)枚举所有等价情况。对于一种情况,强制了一个等价类里面的数都要相同,其它的可以相同也可以不同。
容斥系数为:$(−1)^{p−等价类个数}(每个等价类大小−1)!之积$。
Grey 码
格雷序列第 i 个是i^(i>>1)
。长为 n 的 01 序列共$2^n$个,下标从$0\dots 2^n-1$。
扩展 Cayley 公式
对于 n 个点,m 个连通块的图,假设每个连通块有 a[i]个点,那么用 s−1 条边把它连通的方案数为$n^{s−2}a[1]a[2]\dots a[m]$。
超立方体
n 维超立方体有$2^{n−i}C(n,i)$个 i 维元素。
枚举位集 I 的非空子集 J
for(J=I; J; J=I&J−1) {}