考虑枚举选出来 \(i\) 个没气的篮球,那么答案可以表示成:
\[\text{ans}=\frac{1}{\dbinom{n}{k}}\sum\limits_{i=0}^{k}\dbinom{m}{i}\dbinom{n-m}{k-i}i^L \]注意到这里的组合数 \(\dbinom{n}{m}\) 在 \(n<m\) 或者 \(m<0\) 时无意义,直接当成 \(0\) 即可。
考虑普通幂转下降幂:
\[i^L=\sum\limits_{j=0}^L\begin{Bmatrix}L\\j\end{Bmatrix}i^{\underline j} \]带入原式有:
\[\begin{aligned}\text{ans}&=\frac{1}{\dbinom{m}{k}}\sum\limits_{i=0}^k\dbinom{m}{i}\dbinom{n-m}{k-i}\sum\limits_{j=0}^L\begin{Bmatrix}L\\j\end{Bmatrix}i^{\underline j}\\&=\frac{1}{\dbinom{m}{k}}\sum\limits_{j=0}^L\begin{Bmatrix}L\\j\end{Bmatrix}\sum\limits_{i=0}^k\dbinom{m}{i}\dbinom{n-m}{k-i}i^{\underline j}\end{aligned} \]根据经典组合恒等式:
\[\begin{aligned}\dbinom{m}{i}i^{\underline j}&=\frac{m!}{i!(m-i)!}\cdot \frac{i!}{(i-j)!}\\&=\frac{m!}{(m-i)!(i-j)!}\\&=\frac{(m-j)!}{(m-i)!(i-j)!}\cdot \frac{m!}{(m-j)!}\\&=\dbinom{m-j}{i-j}m^{\underline j}\end{aligned} \]代入原式得:
\[\begin{aligned}\text{ans}&=\frac{1}{\dbinom{m}{k}}\sum\limits_{j=0}^L\begin{Bmatrix}L\\j\end{Bmatrix}\sum\limits_{i=0}^k\dbinom{n-m}{k-i}\dbinom{m-j}{i-j}m^{\underline j}\\&=\frac{1}{\dbinom{m}{k}}\sum\limits_{j=0}^L\begin{Bmatrix}L\\j\end{Bmatrix}m^{\underline j}\sum\limits_{i=0}^k\dbinom{n-m}{k-i}\dbinom{m-j}{i-j}\\&=\frac{1}{\dbinom{m}{k}}\sum\limits_{j=0}^L\begin{Bmatrix}L\\j\end{Bmatrix}m^{\underline j}\dbinom{n-j}{k-j}\end{aligned} \]第三步运用了范德蒙德卷积。
于是我们只需要求出第 \(L\) 行的斯特林数值,就可以通过 \(O(N)\) 预处理阶乘及其逆元,对于每个询问 \(O(L)\) 得出答案。
这是个经典 trick,通过二项式反演以及 NTT 可以 \(O(L\log L)\)求出,可以看 P5395 第二类斯特林数·行,这里不多赘述。
总复杂度 \(O(N+L(\log L+q))\)。
// Problem: P2791 幼儿园篮球题
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2791
// Memory Limit: 222 MB
// Time Limit: 1110 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
namespace vbzIO {
char ibuf[(1 << 20) + 1], *iS, *iT;
#if ONLINE_JUDGE
#define gh() (iS == iT ? iT = (iS = ibuf) + fread(ibuf, 1, (1 << 20) + 1, stdin), (iS == iT ? EOF : *iS++) : *iS++)
#else
#define gh() getchar()
#endif
#define mt make_tuple
#define mp make_pair
#define fi first
#define se second
#define pc putchar
#define pb emplace_back
#define ins insert
#define era erase
typedef tuple<int, int, int> tu3;
typedef pair<int, int> pi;
inline int rd() {
char ch = gh();
int x = 0;
bool t = 0;
while (ch < '0' || ch > '9') t |= ch == '-', ch = gh();
while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = gh();
return t ? ~(x - 1) : x;
}
inline void wr(int x) {
if (x < 0) {
x = ~(x - 1);
putchar('-');
}
if (x > 9)
wr(x / 10);
putchar(x % 10 + '0');
}
}
using namespace vbzIO;
const int N = 2e5 + 200;
const int M = 2e7 + 200;
const int P = 998244353;
const int G = 114514;
int q, n, len = 1, lim, a[N << 2], b[N << 2], tr[N << 2], fac[M], ifac[M];
int qpow(int p, int q) {
int res = 1;
for (; q; q >>= 1, p = 1ll * p * p % P)
if (q & 1) res = 1ll * res * p % P;
return res;
}
const int iG = qpow(G, P - 2);
void init(int lim) {
fac[0] = 1;
for (int i = 1; i <= lim; i++)
fac[i] = 1ll * fac[i - 1] * i % P;
ifac[lim] = qpow(fac[lim], P - 2) % P;
for (int i = lim - 1; ~i; i--)
ifac[i] = 1ll * ifac[i + 1] * (i + 1) % P;
}
int C(int n, int m) {
if (n < m || m < 0) return 0;
return 1ll * fac[n] * ifac[m] % P * ifac[n - m] % P;
}
void NTT(int *f, int op) {
for (int i = 0; i < len; i++)
if (i < tr[i]) swap(f[i], f[tr[i]]);
for (int o = 2, k = 1; k < len; o <<= 1, k <<= 1) {
int tg = qpow((~op) ? G : iG, (P - 1) / o);
for (int i = 0; i < len; i += o) {
for (int j = 0, w = 1; j < k; j++, w = 1ll * w * tg % P) {
int x = f[i + j], y = 1ll * f[i + j + k] * w % P;
f[i + j] = (x + y) % P, f[i + j + k] = (x - y + P) % P;
}
}
}
if (~op) return;
int iv = qpow(len, P - 2);
for (int i = 0; i < len; i++)
f[i] = 1ll * f[i] * iv % P;
}
int main() {
int t = max(rd(), rd());
q = rd(), n = rd(), init(t);
for (int i = 0, g = 1; i <= n; i++, g = P - g)
a[i] = 1ll * g * ifac[i] % P, b[i] = 1ll * qpow(i, n) * ifac[i] % P;
while (len <= (n << 1)) len <<= 1, lim++;
for (int i = 0; i < len; i++)
tr[i] = (tr[i >> 1] >> 1) | ((i & 1) << (lim - 1));
NTT(a, 1), NTT(b, 1);
for (int i = 0; i < len; i++)
a[i] = 1ll * a[i] * b[i] % P;
NTT(a, -1);
while (q--) {
int x = rd(), y = rd(), z = rd();
int res = 0;
for (int i = 0; i <= min(min(n, x), min(y, z)); i++)
(res += 1ll * a[i] * fac[y] % P * ifac[y - i] % P * C(x - i, z - i) % P) %= P;
wr(1ll * res * qpow(C(x, z), P - 2) % P), pc('\n');
}
return 0;
}
标签:frac,dbinom,limits,int,Luogu,sum,篮球,Bmatrix,2791
From: https://www.cnblogs.com/Ender32k/p/17569726.html