题解: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}\)。所以,我们有

\[g_i=\binom{y}{i}\times\binom{n-2i+k-1}{k-1} \]

套一个裸的二项式反演上去就有

\[ans=\sum_{i=0}^{y}(-1)^ig_i \]

于是我们就轻松切了这道题。时间复杂度为 \(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;
}
posted @ 2024-12-21 00:42  P2441M  阅读(41)  评论(0)    收藏  举报