uoj390
题意
有 \(N\ +\ 1\) 个空格位于 \(n\) 列上,每列有 \(a_i\) 个空格。现在有 \(N\) 个人来,每个人会在还有空格的列中随机选出一列并占据这列的一个空格。
问占据了 \(N\) 个空格后,每一列还有空格的概率是多少。
\(1\ \leq\ n,\ a_i,\ \leq\ 30,\ \sum_i\ a_i\ =\ N\ +\ 1\)
做法1
对每一列 \(i\) 求答案。可以将问题转化为每次从 \(n\) 列中挑选一列,若这列无空格则再选,直到有空格位置。这样由于任意时刻有空格的列相对比例不变,所以不影响答案。
所求答案即为 \(p_1,\ p_2,\ ...,\ p_K\),其中 \(\forall\ j\ \neq\ i,\ j\) 在 \(p\) 中出现了至少 \(a_j\) 次,i 出现了 \(a_i\ -\ 1\) 次。答案即为 \(\sum_p\ \frac{1}{n^{K\ +\ 1}}\)。
由于是排列,所以考虑借助 EGF 来想。令 \(F_j(x)\ =\ \sum_{k\ \geq\ a_j}\ \frac{x^k}{k!\ n^k},\ \forall\ j\ \neq\ i\)。则可以发现 \(k!\ [x^k]\ F_a(x)\ F_b(x)\) 恰好为这两个数长度为 \(k\) 的贡献。
令 \(G_j(x)\ =\ \sum_{k\ <\ a_j}\ \frac{x^k}{k!\ n^k},\ \forall\ j\ \neq\ i,\ F(x)\ =\ \frac{x^{a_i\ -\ 1}}{n^{a_i}\ (a_i\ -\ 1)!}\ \Pi_{j\ \neq\ i}\ F_j(x)\ =\ \frac{x^{a_i\ -\ 1}}{n^{a_i}\ (a_i\ -\ 1)!}\ \Pi_{j\ \neq\ i}\ (e^{\frac{x}{n}}\ -\ G_j(x))\),所求即为 \(\sum_i\ [x^i]F(x)\ i!\)。
设 \(F(x)\ =\ \sum_{i,\ j}\ k_{i,\ j}\ x^i\ e^{\frac{jx}{n}}\),现在对每个 \(k_{i,\ j}\) 要计算贡献。由 wolfram 可知当 \(|x|\ <\ 1\) 时,\(\sum_{i\ \geq\ 0}\ \frac{x^i\ (i\ +\ k)!}{i!}\ =\ k!\ (1\ -\ x)^{-k\ -\ 1}\),所以 \(k_{i,\ j}\) 贡献为 \(k_{i,\ j}\ (\frac{n}{n\ -\ j})^{i\ +\ 1}\ i!\)。
可以通过预处理来优化复杂度。
代码
#include <bits/stdc++.h>
#ifdef __WIN32
#define LLFORMAT "I64"
#else
#define LLFORMAT "ll"
#endif
using namespace std;
const int mod = 998244353;
int main() {
auto pow_mod = [&](int x, int n) {
int y = 1;
while(n) {
if(n & 1) y = (long long) y * x % mod;
n >>= 1;
x = (long long) x * x % mod;
}
return y;
};
int n, m = 0, N = 0; cin >> n;
vector<int> a(n);
for (int i = 0; i < n; ++i) cin >> a[i], N += a[i], m = max(m, a[i]);
vector<int> fac(N + 1), ifac(N + 1), ipw(m + 1);
fac[0] = 1; for (int i = 1; i <= N; ++i) fac[i] = (long long) fac[i - 1] * i % mod;
ifac[N] = pow_mod(fac[N], mod - 2); for (int i = N; i; --i) ifac[i - 1] = (long long) ifac[i] * i % mod;
ipw[0] = 1; ipw[1] = pow_mod(n, mod - 2); for (int i = 2; i <= m; ++i) ipw[i] = (long long) ipw[i - 1] * ipw[1] % mod;
function<void()> solve = [&]() {
vector<vector<int> > f(a[0], vector<int>(n, 0));
f[a[0] - 1][0] = (long long) ifac[a[0] - 1] * ipw[a[0]] % mod;
for (int i = 1; i < n; ++i) {
vector<vector<int> > g(f.size() + a[i] - 1, vector<int>(n, 0));
for (int j = 0; j < f.size(); ++j) for (int k = 0; k < a[i]; ++k) {
int x = -(long long) ifac[k] * ipw[k] % mod;
for (int y, l = 0; l < n; ++l) if(y = f[j][l]) g[j + k][l] = ((long long) x * y + g[j + k][l]) % mod;
}
for (int j = 0; j < f.size(); ++j) for (int k = 0; k < n - 1; ++k) g[j][k + 1] = (g[j][k + 1] + f[j][k]) % mod;
f = g;
}
int ans = 0;
for (int i = 0; i < f.size(); ++i) for (int k, j = 0; j < f[i].size(); ++j) if(k = f[i][j]) {
ans = ((long long) pow_mod(n, i + 1) * pow_mod(pow_mod(n - j, i + 1), mod - 2) % mod * fac[i] % mod * k + ans) % mod;
}
cout << (ans + mod) % mod << ' ';
return;
};
for (int i = 0; i < n; ++i) swap(a[i], a[0]), solve();
return 0;
}