CFgym103428M 810975

0x00 Outline

炉 石 圣 经 810975

\(n\)\(m\)\(k\) 连鸡的方案数.

0x01

原题需要保证至少有一个 \(k\) 连鸡,不妨先分别求出 \(n\)\(m\) 鸡 不超过 \(k\) 连鸡和不超过 \(k-1\) 连鸡的方案数,二者相减即为答案.

二者求法类似,以前者为例:

考虑在 \(n-m\)0 之间的 \(n-m+1\) 个空中插入 \(m\)1,同一个空中不超过 \(k\)1,即:

\[\sum_{i=1}^{n-m+1} x_i = m \quad (x_i \le k) \]

考虑容斥:

  1. 枚举共 \(i\) 个空中超过了 \(k\)1,有 \(C_{n-m+1}^i\) 种选法.

  2. 从这 \(i\) 个空中分别拿掉 \(k+1\)1,转化为 \(n-m+1\) 个空中插入 \(m-i(k+1)\)1 且没有限制的情况,插板法得方案数为 \(C_{n-i(k+1)}^{n-m}\).

\[\text{ans}_k = \sum_{i=0}^{n-m+1} (-1)^i \cdot C_{n-m+1}^i \cdot C_{n-i(k+1)}^{n-m} \]

0x02 Code

#include <bits/stdc++.h>
#define int long long
using namespace std;

inline int read(){
	int x = 0, f = 1; char c = getchar();
	while(isdigit(c)^1) f &= (c!=45), c = getchar();
	while(isdigit(c)) x = (x<<1) + (x<<3) + (c^48), c = getchar();
	return f ? x : -x;
}

const int maxn = 200005;
const int mod = 998244353;
int n, m, k, fac[maxn], ifac[maxn];

inline int quickpow(const int &a, int b=mod-2, int P=mod){
	int c = 1;
	for(int x=a; b; x=x*x%P, b>>=1)
		if(b&1) c = c * x % P;
	return c;
}

inline int C(const int &n, const int &m, int P=mod){
	return (n<0 || m<0 || n<m) ? 0 : fac[n] * ifac[m] % P * ifac[n-m] % P;
}

inline void init(int n){
	fac[0] = 1; for(int i=1; i<=n; ++i) fac[i] = i * fac[i-1] % mod;
	ifac[n] = quickpow(fac[n]); for(int i=n; i; --i) ifac[i-1] = i * ifac[i] % mod;
}

inline int calc(int x){
	int res = 0;
	for(int i=0; i<=n-m+1; ++i) res = ((res+((i&1)?-1:1)*C(n-m+1, i)%mod*C(n-i*x, n-m)%mod)%mod+mod) % mod;
	return res;
}

signed main(){
#ifndef ONLINE_JUDGE
	freopen("test.in", "r", stdin);
#endif
	n = read(), m = read(), k = read();
	if(n<m || m<k) puts("0"), exit(0);
	init(200000), printf("%lld\n", (calc(k+1)-calc(k)+mod)%mod);
	return 0;
}
posted @ 2022-04-13 09:09  johnsmith0x3f  阅读(83)  评论(0)    收藏  举报