CF1943D1 Counting Is Fun (Easy Version) - Solution
这是积木大赛,所以如果没有
但是有
对,就是这种类似 CF Logo 的图形。
翻译成人话就是:存在
首先无解是一定的,这种情况下
那不存在这种情况就合法了吗?这也是容易理解的。
根据积木大赛的结论,我们考虑包含
好,现在就是计数所有满足
此时有一个 naive 的做法就是设个
但还是不够切这道题。
从转移方程上找东西显然是无用功,只能继续发掘性质。比如——考虑容斥。
发现一个重要性质:不合法的位置不会相邻。
很简单,因为你随便考虑某两个相邻的不合法位置,假设分别是
则
不合法位置不相邻,给我们优化复杂度以极大方便。
一个明显的好处就是我们可以直接从
设
则有:
因为
前面一坨直接记录和,后面一坨倒序枚举
时间复杂度
#include <bits/stdc++.h>
#define X first
#define Y second
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
using namespace std;
using ld = double;
typedef long long int ll;
using pdi = pair<ld, int>;
using vec = vector<int>;
constexpr int maxn = 3e3 + 10;
int T, n, k, mod, f[maxn][maxn], g[maxn][maxn];
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d%d%d", &n, &k, &mod);
rep(i, 0, n + 1) rep(j, 0, k) f[i][j] = g[i][j] = 0;
f[0][0] = 1; rep(i, 0, k) f[1][i] = g[0][i] = 1, g[1][i] = i + 1;
rep(i, 2, n + 1) {
int s = 0;
per(j, k, 0) f[i][j] = ((ll)g[i - 1][k] - (s = (s + g[i - 2][k - j - 1]) % mod) + mod) % mod;
rep(j, 0, k) g[i][j] = ((j ? g[i][j - 1] : 0) + f[i][j]) % mod;
}
printf("%d\n", f[n + 1][0]);
}
return 0;
}
同类题(lca 长训营入营测试赛,侵删):给定长度为