题解:ARC102E Stop. Otherwise...
简述题意
有 \(n\) 个互不区分的骰子,每个骰子有 \(K\) 个面,上面有 \(1\) 到 \(K\)。两个局面不同当且仅当存在一个点数 \(i\) 使得投出 \(i\) 的数量不同。对于 \([2,2K]\) 中的每一个数 \(x\),求出任意投这个 \(n\) 个骰子使得不存在任意两个骰子的点数和为 \(x\) 的方案数。答案对 \(998244353\) 取模。
题解
有 DP 做法,但我直接大力容斥不用动脑。
对于每个 \(x\in[2,2K]\) 求解答案。不存在任意两个骰子的点数和为 \(x\),等价于点数集合恰好 \(0\) 对 \(p\) 和 \(x-p\) 同时存在。可以发现我们更容易计算至少 \(i\) 对 \(p\) 和 \(x-p\) 同时存在,所以考虑二项式反演计算这个东西。
我们先求出有整数对 \((p,x-p)\) 的个数 \(y\),其中 \(p\leq x-p\)。容易列出不等式 \(1\leq p\leq x-p\leq k\),其解集为 \(\left[\max(x-k,1),\lfloor x/2\rfloor\right]\),因此 \(y=\lfloor x/2\rfloor-\max(x-k,1)+1\)。
然后我们组合计算至少 \(i\) 对 \(p\) 和 \(x-p\) 同时存在的方案数 \(g_i\)。选出这些数对显然有 \(\binom{y}{i}\) 种方案。对于剩下的 \(n-2i\) 个骰子,它们投出的数无限制,总方案数可以插板算出来,等价于把 \(n-2i\) 个骰子分成 \(k\) 组(分到第 \(j\) 组表示这个骰子投出来的数是 \(j\)),组内可空,方案数为 \(\binom{n-2i+k-1}{k-1}\)。所以,我们有
套一个裸的二项式反演上去就有
于是我们就轻松切了这道题。时间复杂度为 \(O(nk)\)。
具体实现时,计算组合数 \(\binom{n}{m}\) 记得在 \(n<m\) 时算作 \(0\)。
代码
#include <iostream>
using namespace std;
#define lowbit(x) ((x) & -(x))
#define add_mod(x, v) (x) = ((ll)(x) + (v)) % MOD
#define mul_mod(x, v) (x) = (1ll * (x) * (v)) % MOD
#define sub_mod(x, v) (x) = (((ll)(x) - (v)) % MOD + MOD) % MOD
#define chk_min(x, v) (x) = min((x), (v))
#define chk_max(x, v) (x) = max((x), (v))
typedef long long ll;
typedef pair<int, int> pii;
const int MAX_S = 4e3 + 5, MOD = 998244353;
int n, k, y;
int fac[MAX_S], inv_fac[MAX_S];
ll ans;
ll quick_power(ll a, ll b) {
ll res = 1;
for (; b; b >>= 1) {
if (b & 1) mul_mod(res, a);
mul_mod(a, a);
}
return res;
}
void preproc(int lim) {
fac[0] = 1;
for (int i = 1; i <= lim; ++i) fac[i] = 1ll * fac[i - 1] * i % MOD;
inv_fac[lim] = quick_power(fac[lim], MOD - 2);
for (int i = lim - 1; i >= 0; --i) inv_fac[i] = 1ll * inv_fac[i + 1] * (i + 1) % MOD;
}
int comb(int n, int m) {
if (n < m) return 0;
return 1ll * fac[n] * inv_fac[m] % MOD * inv_fac[n - m] % MOD;
}
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr);
cin >> k >> n;
preproc(n + k);
for (int x = 2; x <= (k << 1); ++x) {
y = (x >> 1) - max(x - k, 1) + 1;
ans = 0;
for (int i = 0, c = 1; i <= y; ++i, c = -c) {
add_mod(ans, 1ll * comb(y, i) * comb(n - (i << 1) + k - 1, k - 1) % MOD * c % MOD);
ans = (ans + MOD) % MOD;
}
cout << ans << '\n';
}
return 0;
}

浙公网安备 33010602011771号