专栏文章
CF 2066D2 Club of Young Aircraft Builders (hard version)
CF2066D2题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mioxn4fs
- 此快照首次捕获于
- 2025/12/03 02:49 3 个月前
- 此快照最后确认于
- 2025/12/03 02:49 3 个月前
说一个看起来暴力得多的做法!
考虑对于 只有在 层飞出的纸飞机数量 时才能飞一个纸飞机。
那么如果知道了当前每个楼层飞出的纸飞机数,考虑找到最小的 满足 层飞出的纸飞机数 ,此时就相当于是只有 层可以飞出纸飞机。
那么如果知道了当前每个楼层飞出的纸飞机数,考虑找到最小的 满足 层飞出的纸飞机数 ,此时就相当于是只有 层可以飞出纸飞机。
发现这就天然的分出了阶段: 层都可以飞纸飞机, 层可以飞纸飞机,一直到最后第 层的纸飞机也飞完结束。
于是考虑记 表示考虑了前 个纸飞机,此时 层还可以飞纸飞机,且 层一共飞了 个纸飞机的方案数。
为了方便转移,考虑延后计算贡献,就是此时不去区分 层具体的分法,到阶段结束时再考虑计算贡献。
具体来说对于转移,考虑分为两种:
为了方便转移,考虑延后计算贡献,就是此时不去区分 层具体的分法,到阶段结束时再考虑计算贡献。
具体来说对于转移,考虑分为两种:
-
,那么直接飞一个纸飞机即可 。
-
,那么之后 这一层就不能飞纸飞机了,考虑枚举 这一层在之前飞了多少个纸飞机。具体来说,记 中 的数量为 , 的数量为 ,那么还有 个纸飞机没有确定,枚举 表示 层的纸飞机数,转移为 。需要注意可能 这一层飞出去了 个纸飞机,所以 的纸飞机数仍为 ,要继续删掉 层。
还需要考虑的是,如果遇到了 ,说明此时 一定能够飞纸飞机,所以 的合法范围应为 。
时状态数 转移 , 时状态数 转移 ,所以总时间复杂度为 。
CPP#include <bits/stdc++.h>
using ll = long long;
constexpr ll mod = 1e9 + 7;
constexpr int maxn = 100 + 2;
constexpr int maxm = 10000 + 5;
ll binom[maxn][maxn];
inline void init() {
for (int i = 0; i < maxn; i++) {
binom[i][0] = 1;
for (int j = 1; j <= i; j++) {
binom[i][j] = (binom[i - 1][j - 1] + binom[i - 1][j]) % mod;
}
}
}
int a[maxm], b[maxn], sum[maxm][maxn];
ll f[maxn][maxn], g[maxn][maxn];
inline void solve() {
int n, c, m;
scanf("%d%d%d", &n, &c, &m);
for (int i = 1; i <= m; i++) scanf("%d", &a[i]);
for (int i = 1; i <= n; i++) {
b[i] = std::count(a + 1, a + m + 1, i);
if (b[i] > c) {
return puts("0"), void();
}
}
for (int i = 1; i <= m; i++) {
memcpy(sum[i], sum[i - 1], sizeof(sum[i]));
for (int j = 1; j <= a[i]; j++) {
sum[i][j]++;
}
}
memset(f, 0, sizeof(f)), f[1][0] = 1;
for (int i = 1; i <= m; i++) {
for (int p = 1; p <= (a[i] == 0 ? n : a[i]); p++) {
for (int x = c; x >= 1; x--) {
f[p][x] = f[p][x - 1];
}
f[p][0] = 0;
}
for (int p = (a[i] == 0 ? n : a[i]) + 1; p <= n + 1; p++) {
memset(f[p], 0, sizeof(ll) * (c + 1));
}
for (int p = 1; p <= n; p++) {
for (int x = b[p]; x <= c - sum[i][p + 1]; x++) {
(f[p + 1][c - x] += f[p][c] * binom[c - sum[i][p]][x - b[p]]) %= mod;
}
f[p][c] = 0;
}
}
printf("%lld\n", f[n + 1][0]);
}
int main() {
init();
int t; scanf("%d", &t);
while (t--) solve();
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...