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)
\]
考虑容斥:
-
枚举共 \(i\) 个空中超过了 \(k\) 个
1,有 \(C_{n-m+1}^i\) 种选法. -
从这 \(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;
}

浙公网安备 33010602011771号