组合数学
组合数学
例1:P3197 [HNOI2008] 越狱
题目简意
有 \(n\) 个房间,每个房间的犯人可以选择 \(m\) 种宗教之一。如果相邻两个房间的犯人信仰同一宗教,则发生越狱。求发生越狱的方案数,对 \(100003\) 取模。
思路分析
直接求发生越狱的方案数较困难,采用正难则反策略:
- 总方案数:每个房间有 \(m\) 种选择,共 \(m^n\) 种。
- 不发生越狱的方案数:第一个房间有 \(m\) 种选择;之后每个房间只要与前一个不同即可,各有 \(m-1\) 种选择,共 \(m \times (m-1)^{n-1}\)。
- 答案 = 总方案数 − 不发生越狱方案数 = \(m^n - m \times (m-1)^{n-1}\)。
注意取模处理,防止结果为负数。
时空复杂度
- 时间复杂度:\(O(\log n)\)(快速幂)
- 空间复杂度:\(O(1)\)
代码
#include <cstdio>
using namespace std;
const int MOD = 100003;
// 快速幂:计算 a^b % MOD
long long qpow(long long a, long long b) {
long long res = 1;
while (b > 0) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
int main() {
long long m, n;
scanf("%lld%lld", &m, &n);
long long total = qpow(m, n); // 总方案数 m^n
long long noEscape = m * qpow(m - 1, n - 1) % MOD; // 不发生越狱 m*(m-1)^(n-1)
long long ans = (total - noEscape + MOD) % MOD;
printf("%lld\n", ans);
return 0;
}
例2:P5664 [CSP-S 2019] Emiya 家今天的饭
题目简意
给定一个 \(n \times m\) 的矩阵,\(a_{i,j}\) 表示用第 \(i\) 种烹饪方法和第 \(j\) 种主要食材可以做出 \(a_{i,j}\) 道不同的菜。要求:
- 选的菜非空;
- 每道菜的烹饪方法互不相同(即每行最多选一个);
- 每种主要食材的菜数不超过选菜总数的一半。
求满足条件的方案总数。
思路分析
采用正难则反:答案 = 所有方案数 − 不合法方案数。
所有方案数:对每行,可以选择不做菜,或从该行 \(m\) 种食材中选一种做一道菜。设 \(sum_i = \sum_{j=1}^{m} a_{i,j}\),则前 \(i\) 行的总方案数为 \(\prod_{i=1}^{n} (sum_i + 1)\)。减去全不选的 1 种空集情况。
不合法方案数:不合法方案中,有且仅有一种食材的出现次数超过总数的一半。枚举这个“超限”食材 \(c\),用 DP 计算:
设 \(dp[d]\) 表示当前考虑前 \(i\) 行,超限食材出现次数 − 其他食材出现次数的差值为 \(d\) 的方案数。
- 不选:差值不变
- 选超限食材 \(c\):差值 \(+1\),方案数乘 \(a_{i,c}\)
- 选其他食材:差值 \(-1\),方案数乘 \((sum_i - a_{i,c})\)
最终差值 \(> 0\) 的方案数即为以 \(c\) 为超限食材的不合法方案数。
将 \(m\) 种食材的不合法方案数求和,用总方案数减去即可。
时空复杂度
- 时间复杂度:\(O(n^2 m)\)
- 空间复杂度:\(O(n)\)(滚动数组优化后)
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 105;
const int MAXM = 2005;
const int MOD = 998244353;
int n, m;
long long a[MAXN][MAXM];
long long sum[MAXN];
long long dp[MAXN * 2]; // 偏移量为 n,差值范围 [-n, n]
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
scanf("%lld", &a[i][j]);
sum[i] = (sum[i] + a[i][j]) % MOD;
}
}
// 1. 计算所有方案数(包含空集)
long long all = 1;
for (int i = 1; i <= n; i++) {
all = all * (sum[i] + 1) % MOD;
}
all = (all - 1 + MOD) % MOD; // 去掉空集
// 2. 计算不合法方案数
long long bad = 0;
for (int c = 1; c <= m; c++) { // 枚举超限食材
memset(dp, 0, sizeof(dp));
dp[n] = 1; // 偏移 n,表示差值为 0
for (int i = 1; i <= n; i++) {
long long other = (sum[i] - a[i][c] + MOD) % MOD;
long long ndp[MAXN * 2] = {0};
for (int d = 0; d <= 2 * n; d++) {
if (dp[d] == 0) continue;
// 不选
ndp[d] = (ndp[d] + dp[d]) % MOD;
// 选超限食材 c
if (d + 1 <= 2 * n) {
ndp[d + 1] = (ndp[d + 1] + dp[d] * a[i][c]) % MOD;
}
// 选其他食材
if (d - 1 >= 0) {
ndp[d - 1] = (ndp[d - 1] + dp[d] * other) % MOD;
}
}
memcpy(dp, ndp, sizeof(dp));
}
// 差值 > 0 的方案数(即超限食材出现次数 > 其他食材出现次数)
for (int d = n + 1; d <= 2 * n; d++) {
bad = (bad + dp[d]) % MOD;
}
}
long long ans = (all - bad + MOD) % MOD;
printf("%lld\n", ans);
return 0;
}
例3:拿糖果
无对应题目(用户提供的题号列表中没有该题)。
例4 / 例11:P1287 盒子与球
题目简意
有 \(r\) 个互不相同的盒子和 \(n\) 个互不相同的球,要将 \(n\) 个球全部放入 \(r\) 个盒子中,不允许有空盒子,求方案数。
思路分析
方法一:容斥原理
- 不考虑空盒限制时,每个球有 \(r\) 种选择,总方案数为 \(r^n\)
- 减去有空盒的情况,用容斥:\[\text{ans} = \sum_{k=0}^{r} (-1)^k \binom{r}{k} (r-k)^n \]其中 \(k\) 表示强制空盒的数量。
方法二:第二类斯特林数 + 排列
- 先将 \(n\) 个不同的球分成 \(r\) 个非空无标号集合,方案数为第二类斯特林数 \(S(n,r)\)
- 再将 \(r\) 个集合分配给 \(r\) 个不同的盒子,乘 \(r!\)
- 答案为 \(S(n,r) \times r!\)
递推式:\(S(i,j) = S(i-1,j-1) + j \times S(i-1,j)\)
时空复杂度
- 时间复杂度:\(O(nr)\)(DP 递推)
- 空间复杂度:\(O(nr)\) 或 \(O(r)\)(滚动数组)
代码(第二类斯特林数 + 排列)
#include <cstdio>
using namespace std;
long long s[15][15]; // s[i][j] = 第二类斯特林数
int main() {
int n, r;
scanf("%d%d", &n, &r);
// 第二类斯特林数递推
s[0][0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= r; j++) {
s[i][j] = s[i - 1][j - 1] + j * s[i - 1][j];
}
}
// 乘以 r!(盒子互不相同)
long long fact = 1;
for (int i = 1; i <= r; i++) fact *= i;
printf("%lld\n", s[n][r] * fact);
return 0;
}
例5:P1450 [HAOI2008] 硬币购物
题目简意
有 4 种面值的硬币,面值分别为 \(c_1, c_2, c_3, c_4\)。给出 \(T\) 组询问,每组给定每种硬币的数量限制 \(d_i\) 和需要凑出的总金额 \(s\),求用不超过数量限制的硬币凑出 \(s\) 的方案数。
思路分析
直接多重背包每组询问都会超时。
容斥原理:
- 先用完全背包预处理出无数量限制时凑出任意金额 \(s\) 的方案数 \(dp[s]\)。
- 对于一组询问,答案 = 无限制方案数 − 某些硬币超限的方案数。
- 若第 \(i\) 种硬币超限,则至少用了 \(d_i+1\) 枚,先强制扣除 \((d_i+1) \times c_i\),剩余金额任意凑。
- 用容斥枚举 4 种硬币超限/不超限的所有 \(2^4\) 种组合:奇数个超限则减,偶数个超限则加。
时空复杂度
- 预处理:\(O(4 \times s_{max})\)
- 每组询问:\(O(2^4) = O(16)\)
- 空间复杂度:\(O(s_{max})\)
代码
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXS = 100000;
long long dp[MAXS + 5];
int c[5], d[5];
int main() {
for (int i = 1; i <= 4; i++) scanf("%d", &c[i]);
// 完全背包预处理:无限制方案数
dp[0] = 1;
for (int i = 1; i <= 4; i++) {
for (int j = c[i]; j <= MAXS; j++) {
dp[j] += dp[j - c[i]];
}
}
int T;
scanf("%d", &T);
while (T--) {
for (int i = 1; i <= 4; i++) scanf("%d", &d[i]);
int s;
scanf("%d", &s);
long long ans = 0;
// 枚举 16 种超限组合(二进制位为 1 表示该硬币超限)
for (int mask = 0; mask < 16; mask++) {
long long remain = s;
int cnt = 0; // 超限硬币个数
for (int i = 1; i <= 4; i++) {
if (mask & (1 << (i - 1))) {
remain -= 1LL * c[i] * (d[i] + 1);
cnt++;
}
}
if (remain < 0) continue;
// 容斥:奇数个超限减,偶数个超限加
if (cnt & 1) ans -= dp[remain];
else ans += dp[remain];
}
printf("%lld\n", ans);
}
return 0;
}
例6:P5520 [yLOI2019] 青原樱
题目简意
有 \(n\) 个花盆排成一行,要种 \(m\) 朵互不相同的花,每朵花不能种在相邻的花盆中,求方案数对 \(mod\) 取模。
思路分析
隔板法(插空法) :
- 先不考虑花的互异性,从 \(n\) 个位置中选出 \(m\) 个互不相邻的位置
- 在 \(n-m\) 个空位(未种花的位置)形成的 \(n-m+1\) 个空隙中,选 \(m\) 个插入花
- 组合数为 \(\binom{n-m+1}{m}\)
- 再乘以 \(m!\)(\(m\) 朵花互不相同)
- 化简:\(\binom{n-m+1}{m} \times m! = \frac{(n-m+1)!}{(n-2m+1)!} = \prod_{i=n-2m+2}^{n-m+1} i\)
时空复杂度
- 时间复杂度:\(O(m)\)(循环累乘)
- 空间复杂度:\(O(1)\)
代码
#include <cstdio>
using namespace std;
int main() {
long long n, m, mod;
// 注意输入格式:第一个数是无用的类型标识,跳过
scanf("%*d%lld%lld%lld", &n, &m, &mod);
long long ans = 1;
// 计算 ∏_{i=n-2m+2}^{n-m+1} i
for (long long i = n - 2 * m + 2; i <= n - m + 1; i++) {
ans = ans * i % mod;
}
printf("%lld\n", ans);
return 0;
}
例7:P4071 [SDOI2016] 排列计数
题目简意
求有多少个 \(1\) 到 \(n\) 的排列,恰好有 \(m\) 个位置满足 \(a_i = i\)(即恰好 \(m\) 个“稳定”位置),答案对 \(10^9+7\) 取模。
思路分析
- 先从 \(n\) 个位置中选出 \(m\) 个稳定位置:\(\binom{n}{m}\)
- 剩下的 \(n-m\) 个位置必须全部错排(没有一个元素在原来的位置)
- 错排数 \(D_k\) 的递推公式:\(D_0 = 1, D_1 = 0, D_k = (k-1)(D_{k-1} + D_{k-2})\)
- 答案 = \(\binom{n}{m} \times D_{n-m}\)
时空复杂度
- 预处理:\(O(N)\)(阶乘、逆元、错排数)
- 每组询问:\(O(1)\)
- 空间复杂度:\(O(N)\)
代码
#include <cstdio>
using namespace std;
const int MAXN = 1000005;
const int MOD = 1000000007;
long long fac[MAXN]; // 阶乘
long long invfac[MAXN]; // 阶乘逆元
long long d[MAXN]; // 错排数
// 快速幂
long long qpow(long long a, long long b) {
long long res = 1;
while (b) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
int main() {
// 预处理阶乘
fac[0] = 1;
for (int i = 1; i < MAXN; i++) fac[i] = fac[i - 1] * i % MOD;
// 预处理阶乘逆元
invfac[MAXN - 1] = qpow(fac[MAXN - 1], MOD - 2);
for (int i = MAXN - 2; i >= 0; i--) {
invfac[i] = invfac[i + 1] * (i + 1) % MOD;
}
// 预处理错排数
d[0] = 1;
d[1] = 0;
for (int i = 2; i < MAXN; i++) {
d[i] = (i - 1) * (d[i - 1] + d[i - 2]) % MOD;
}
int T;
scanf("%d", &T);
while (T--) {
int n, m;
scanf("%d%d", &n, &m);
// C(n, m) = n! / (m! * (n-m)!)
long long comb = fac[n] * invfac[m] % MOD * invfac[n - m] % MOD;
long long ans = comb * d[n - m] % MOD;
printf("%lld\n", ans);
}
return 0;
}
例8:P1313 [NOIP 2011 提高组] 计算系数
题目简意
给定多项式 \((ax + by)^k\),求展开后 \(x^n y^m\) 项的系数,对 \(10007\) 取模。
思路分析
由二项式定理:
$ x^n y^m $ 项对应 \(i = n\),\(k-i = m\),系数为:
其中 \(\binom{k}{n}\) 可用杨辉三角(组合数递推)求得,\(a^n\) 和 \(b^m\) 用快速幂。
时空复杂度
- 时间复杂度:\(O(k^2 + \log n + \log m)\)
- 空间复杂度:\(O(k^2)\)
代码
#include <cstdio>
using namespace std;
const int MOD = 10007;
int c[1005][1005];
// 快速幂
int qpow(int a, int b) {
int res = 1;
a %= MOD;
while (b > 0) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
int main() {
int a, b, k, n, m;
scanf("%d%d%d%d%d", &a, &b, &k, &n, &m);
// 杨辉三角求组合数 C(k, n)
c[0][0] = 1;
for (int i = 1; i <= k; i++) {
c[i][0] = c[i][i] = 1;
for (int j = 1; j < i; j++) {
c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % MOD;
}
}
int ans = c[k][n];
ans = ans * qpow(a, n) % MOD;
ans = ans * qpow(b, m) % MOD;
printf("%d\n", ans);
return 0;
}
例9:CF1332E Height All the Same
题目简意
有一个 \(n \times m\) 的网格,每个格子初始高度在 \([L, R]\) 范围内任意。每次操作可以:
- 选择一个格子,将其高度 \(+2\)
- 选择两个相邻格子,将两者高度均 \(+1\)
问有多少种初始高度方案,能够通过若干次操作使所有格子高度相同。
思路分析
关键观察:结果只与高度的奇偶性有关。
- 操作 1(\(+2\))不改变奇偶性
- 操作 2(相邻两个 \(+1\))同时翻转两个相邻格子的奇偶性
问题转化为:能否通过翻转相邻格子的奇偶性,使整个网格奇偶性一致。
- 若 \(n \times m\) 为奇数:任何奇偶性分布都可以调整为全奇或全偶,方案数为 \((R-L+1)^{nm}\)
- 若 \(n \times m\) 为偶数:需要奇数个数的格子数量为偶数。总方案数为 \(\frac{(R-L+1)^{nm} + (R-L+1)^{nm/2} \times [奇偶数量相等时的调整]}{2}\)
简化结论:
- 若 \(nm\) 为奇数:\(ans = (R-L+1)^{nm}\)
- 若 \(nm\) 为偶数:\(ans = \frac{(R-L+1)^{nm} + (R-L+1)^{nm/2} \times (奇偶个数各半的调整)}{2}\)
时空复杂度
- 时间复杂度:\(O(\log(nm))\)(快速幂)
- 空间复杂度:\(O(1)\)
代码
#include <cstdio>
using namespace std;
const int MOD = 998244353;
long long qpow(long long a, long long b) {
long long res = 1;
a %= MOD;
while (b > 0) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
int main() {
long long n, m, L, R;
scanf("%lld%lld%lld%lld", &n, &m, &L, &R);
long long cnt = R - L + 1;
long long cells = n * m;
if (cells & 1) {
// 格子总数为奇数:所有方案都可行
printf("%lld\n", qpow(cnt, cells));
} else {
// 格子总数为偶数
long long even = cnt / 2; // 偶数高度的个数
long long odd = cnt - even; // 奇数高度的个数
// 公式:(cnt^cells + (even - odd)^cells) / 2
long long ans = (qpow(cnt, cells) + qpow((even - odd + MOD) % MOD, cells)) % MOD;
ans = ans * qpow(2, MOD - 2) % MOD; // 乘以 2 的逆元
printf("%lld\n", ans);
}
return 0;
}
例10:P1044 [NOIP 2003 普及组] 栈
题目简意
有 \(n\) 个数依次入栈,问有多少种不同的出栈序列。
思路分析
这是经典的卡特兰数问题。
\(n\) 个数的出栈序列数为第 \(n\) 个卡特兰数:
递推公式:\(C_0 = 1\),\(C_n = \sum_{i=0}^{n-1} C_i \times C_{n-1-i}\)
也可以理解为:第一个入栈的元素第 \(k\) 个出栈,则前 \(k-1\) 个和后 \(n-k\) 个独立,方案数为 \(C_{k-1} \times C_{n-k}\),求和得递推式。
时空复杂度
- 时间复杂度:\(O(n^2)\)(递推)
- 空间复杂度:\(O(n)\)
代码
#include <cstdio>
using namespace std;
long long catalan[20];
int main() {
int n;
scanf("%d", &n);
catalan[0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j < i; j++) {
catalan[i] += catalan[j] * catalan[i - 1 - j];
}
}
printf("%lld\n", catalan[n]);
return 0;
}
其他题目(思维导图中未作为例题,但用户列表中包含)
以下题目在思维导图中有对应的知识点(容斥、卡特兰数、斯特林数等),但未作为例题列出,简要给出题解。
P2567 [SCOI2010] 幸运数字
题目简意
定义“幸运数字”为只包含数字 6 和 8 的数(如 6, 8, 66, 68, 86, 88...)。一个数是“近似幸运数字”当且仅当它是某个幸运数字的倍数。求区间 \([L, R]\) 内近似幸运数字的个数。
思路分析
- DFS 枚举所有幸运数字(\(2^{10}\) 级别)
- 去掉有倍数关系的幸运数字(只保留最小的那个)
- 容斥原理求 \([1, x]\) 内近似幸运数字个数:枚举幸运数字子集,求 LCM,用 \(x / LCM\) 得到该子集的倍数个数,奇数个加,偶数个减
- 答案 = \(calc(R) - calc(L-1)\)
P5505 [JSOI2011] 分特产
题目简意
有 \(n\) 个有标号的同学和 \(m\) 种特产,第 \(i\) 种特产有 \(a_i\) 个(同种特产完全相同)。将特产全部分给同学,要求每个同学至少分到一个特产,求方案数。
思路分析
容斥:至少 \(i\) 个同学没有分到特产。
- 先选出 \(i\) 个同学为空:\(\binom{n}{i}\)
- 剩下的 \(n-i\) 个同学分配所有特产:每种特产独立分配,第 \(j\) 种特产有 \(a_j\) 个,分给 \(n-i\) 个人的方案数为 \(\binom{a_j + n - i - 1}{n - i - 1}\)(隔板法)
- 至少 \(i\) 个同学为空的方案数 = \(\binom{n}{i} \times \prod_{j=1}^{m} \binom{a_j + n - i - 1}{n - i - 1}\)
- 容斥:\(ans = \sum_{i=0}^{n} (-1)^i \times \text{至少 i 个同学为空的方案数}\)
P3223 [HNOI2012] 排队
题目简意
\(n\) 个男生、\(m\) 个女生、2 个老师排队,要求任意两个女生不能相邻,两个老师不能相邻,求方案数。
思路分析
分类讨论:
- 先排男生和老师(把老师当特殊男生):\(n+2\) 个人排列,再插入女生
- 用总方案 − 老师相邻的方案
具体:
- 先排 \(n\) 个男生:\(n!\) 种,形成 \(n+1\) 个空位
- 插入 2 个老师:\(A_{n+1}^2\) 种(不能相邻自动满足,因为插在不同空位)
- 再插入 \(m\) 个女生:在 \(n+3\) 个位置中选 \(m\) 个不相邻位置:\(\binom{n+3}{m} \times m!\)
但需排除老师相邻的情况,用捆绑法处理。
注意:答案可能很大,需要高精度。
P2822 [NOIP 2016 提高组] 组合数问题
题目简意
有 \(T\) 组询问,每组给定 \(n, m\),求有多少对 \((i, j)\) 满足 \(0 \le j \le i \le n\) 且 \(\binom{i}{j}\) 是 \(k\) 的倍数。
思路分析
- 预处理组合数 \(C[i][j]\) 对 \(k\) 取模:\(C[i][j] = (C[i-1][j-1] + C[i-1][j]) \bmod k\)
- 若 \(C[i][j] == 0\),则该组合数是 \(k\) 的倍数
- 二维前缀和 \(sum[i][j]\) 表示 \(\binom{0..i}{0..j}\) 中为 \(k\) 的倍数的个数
- 每组询问 \(O(1)\) 回答
P3214 [HNOI2011] 卡农
题目简意
从集合 \(\{1, 2, ..., n\}\) 的所有非空子集中选出 \(m\) 个互不相同的子集(集合之间无序),要求每个元素在所有选出的子集中出现的总次数为偶数,求方案数。
思路分析
- 先处理无序:先按有序计算,最后除以 \(m!\)
- 设 \(f[i]\) 表示选 \(i\) 个有序子集满足条件的方案数
- 前 \(i-1\) 个集合任意选:\(P(2^n-1, i-1)\) 种
- 第 \(i\) 个集合由前 \(i-1\) 个集合唯一确定(保证每个元素出现偶数次)
- 减去第 \(i\) 个集合为空集的情况(空集不允许)
- 减去第 \(i\) 个集合与前面某个集合重复的情况
- 递推式:\(f[i] = P(2^n-1, i-1) - f[i-1] - (i-1)(2^n - i + 1) f[i-2]\)
- 答案 = \(f[m] \times inv(m!)\)
P2532 [AHOI2012] 树屋阶梯
题目简意
用 \(n\) 个大小相同的矩形钢材搭建一个 \(n\) 层的阶梯形状(每层比上一层多一块),求不同搭建方案数。
思路分析
卡特兰数。
设 \(f[n]\) 为 \(n\) 层阶梯的方案数。考虑左下角最大的矩形,枚举其大小 \(i\),则:
这是卡特兰数的递推式。
注意:\(n\) 最大为 \(500\),答案巨大,需要高精度。
P3200 [HNOI2009] 有趣的数列
题目简意
称一个长度为 \(2n\) 的数列 \(a_1, a_2, ..., a_{2n}\) 是“有趣的”,如果:
- \(a_1, a_3, ..., a_{2n-1}\)(奇数位)和 \(a_2, a_4, ..., a_{2n}\)(偶数位)都单调递增
- 对任意 \(i\),\(a_{2i-1} < a_{2i}\)
求有趣的数列个数。
思路分析
卡特兰数。
将 \(1 \sim 2n\) 依次填入奇数位和偶数位,奇数位在任何时刻的数量 \(\ge\) 偶数位数量,等价于 Catalan 数第 \(n\) 项。
注意:模数 \(p\) 不一定是质数,不能直接用逆元。用质因数分解计算组合数 \(\frac{1}{n+1}\binom{2n}{n}\)。
CF1278F Cards
题目简意
有一副 \(m\) 张牌的牌堆,其中一张是王牌。进行 \(n\) 次独立实验:每次洗牌后看第一张牌,若是王牌则记录。设 \(x\) 为 \(n\) 次中王牌出现在第一张的次数,求 \(E(x^k)\)。
思路分析
利用第二类斯特林数降幂:
其中 \(S(k, j)\) 为第二类斯特林数。
\(i\) 服从二项分布 \(B(n, \frac{1}{m})\):
代入降幂公式化简即可。
P3228 [HNOI2013] 数列
题目简意
求长度为 \(k\) 的正整数序列 \(a_1, a_2, ..., a_k\) 的个数,满足:
- \(1 \le a_1 \le n\)
- \(1 \le a_i - a_{i-1} \le m\)(\(2 \le i \le k\))
思路分析
考虑差分序列 \(b_i = a_{i+1} - a_i\)(\(1 \le i \le k-1\)),每个 \(b_i \in [1, m]\)。
对于一组确定的差分 \(b_1, ..., b_{k-1}\),\(a_1\) 的取值范围为 \([1, n - \sum b_i]\),共有 \(n - \sum b_i\) 种取值。
总方案数:
化简得:
CF961G Partitions
题目简意
将 \(n\) 个有标号的元素划分为 \(k\) 个非空无标号集合(即集合划分),每个元素 \(i\) 有权值 \(w_i\)。一个划分的权值定义为 \(\sum_{S \in \text{划分}} |S| \cdot \sum_{i \in S} w_i\)。求所有划分的权值和。
思路分析
考虑每个元素的贡献。
元素 \(i\) 的贡献 = \(w_i \times\)(所有划分中,\(i\) 所在集合大小之和)
对所有元素求和:
其中 \(S\) 为第二类斯特林数。
等价地:
浙公网安备 33010602011771号