HDU-6397(2018 Multi-University Training Contest 8) Character Encoding(生成函数+组合数学)
题意
从$0$到$n-1$的数字里可重复的取至多$m$个数的和等于$k$的方案数。
思路
显然的生成函数的思路为构造
$(1+x+x^{2}+...+x^{n-1})^{m}$
那么$x^{k}$的系数即答案。等比数列求和后得到
$ \frac {(1-x^n)^m} {(1-x)^m}$
对分子二项式展开得到
$(1-x^n)^m = \sum_{i=0}^m C_m^{i}(-1)^i * x^{n*i}$
对分母根据泰勒展开得到
$(1-x)^{-m} = \sum_{j = 0}^{\infty }C_{m+j-1}^{j}x^{j}$
代码
#include <bits/stdc++.h> #define DBG(x) cerr << #x << " = " << x << endl; using namespace std; const int N = 200000 + 5; const int mod = 998244353; typedef long long LL; int t, n, m, k; LL fac[N], invf[N]; LL add(LL a, LL b) { LL res = a + b; if(res < 0) res += mod; return res % mod; } LL mul(LL a, LL b) { LL res = a * b; if(res < 0) res += mod; return res % mod; } LL qpow(LL a, LL b) { LL res = 1; while(b) { if(b & 1) res = mul(res, a); a = mul(a, a); b /= 2; } return res; } void init() { fac[0] = fac[1] = 1; for(int i = 2; i < N; i++) fac[i] = mul(fac[i - 1], 1LL * i); invf[N - 1] = qpow(fac[N - 1], mod - 2); for(int i = N - 2; i >= 0; i--) invf[i] = mul(invf[i + 1], 1LL * i + 1); } LL C(int n, int m) { if(n < 0 || m < 0 || n < m) return 0; return mul(fac[n], mul(invf[m], invf[n - m])); } int main() { init(); scanf("%d", &t); while(t--) { LL ans = 0; scanf("%d%d%d", &n, &m, &k); for(LL i = 0; k - n * i >= 0; i++) { LL j = k - n * i; LL tmp = (i % 2 == 0 ? 1 : -1); ans = add(ans, mul(tmp, mul(C(m, i), C(m + j - 1, m - 1)))); } printf("%lld\n", ans % mod); } return 0; }