[ABC297F] Minimum Bounding Box 2

也许更好的阅读体验

\(\mathcal{Description}\)
在一个 \(H\)\(W\) 列的网格图上随机选择 \(K\) 个点。定义当前局面的分数为最小的可以围住这 \(K\) 个点的矩形的面积。

请求出所有局面中分数的期望值,输出时对 \(998244353\)取模。

\(\mathcal{Solution}\)
先说经典的容斥方法,考虑围住这\(k\)个点的矩形的大小为\(n *m\)
\(k\)个点全部落在这个矩形范围内的方案数为\(\begin{pmatrix}nm\\ k\end{pmatrix}\)
接下来考虑围住\(k\)个点的最小矩形并不是\(n *m\)的方案数
而这种情况下,一定有一条边上没有点
容斥的方法就出来了,每次考虑几条边上没有点然后考虑一下是什么样的情况,如何加减即可

另一种方法是直接推
\(f[i][j]\)表示围住\(k\)个点的矩形大小为\(i *j\)的方案数
则很容易有

\[f[i][j] = \begin{pmatrix}ij\\ k\end{pmatrix}-\sum\limits_{p = 1}^{i}\sum\limits_{q=1}^{j}(i-p+1)(j-q+1)f[p][q] \]

复杂度是\(O(n^4)\)的,对这个式子变形

\[f[i][j] = \begin{pmatrix}ij\\ k\end{pmatrix}-\sum\limits_{p = 1}^{i}\sum\limits_{q=1}^{j}[(i+1)(j+1)-(j+1)p-(i+1)q+pq]f[p][q] \]

其中\(i,j\)都可看为常量,我们只需维护这几个前缀和就可以方便的转移了:\(if[i][j],\ jf[i][j]\ ,f[i][j],\ ijf[i][j]\)

\(\mathcal{Code}\)

#include <iostream>
using namespace std;
const int mod = 998244353;
const int maxn = 1003;
const int maxm = 1000006;
int n, m, k, ans;
int f[maxn][maxn], s[maxn][maxn], si[maxn][maxn], sj[maxn][maxn], sij[maxn][maxn];
int fac[maxm], ifac[maxm];
void add (int &x, int y){ x = ((x + y) % mod + mod) % mod; }
int C (int n, int m)
{
    if (n < m)  return 0;
    return 1ll * fac[n] * ifac[m] % mod * ifac[n - m] % mod;
}
int main ()
{
    cin >> n >> m >> k;
    fac[0] = ifac[0] = ifac[1] = 1;
    for (int i = 1; i <= 1e6; ++i)  fac[i] = 1ll * fac[i - 1] * i % mod;
    for (int i = 2; i <= 1e6; ++i)  ifac[i] = (mod - 1ll * mod / i * ifac[mod % i] % mod) % mod;
    for (int i = 1; i <= 1e6; ++i)  ifac[i] = 1ll * ifac[i - 1] * ifac[i] % mod;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j) {
            f[i][j] = C(i * j, k);
            add(s[i][j], ((s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1]) % mod + mod) % mod);
            add(si[i][j], ((si[i - 1][j] + si[i][j - 1] - si[i - 1][j - 1]) % mod + mod) % mod);
            add(sj[i][j], ((sj[i - 1][j] + sj[i][j - 1] - sj[i - 1][j - 1]) % mod + mod) % mod);
            add(sij[i][j], ((sij[i - 1][j] + sij[i][j - 1] - sij[i - 1][j - 1]) % mod + mod) % mod);

            add(f[i][j], -1ll * (i + 1) * (j + 1) * s[i][j] % mod);
            add(f[i][j], 1ll * (i + 1) * sj[i][j] % mod);
            add(f[i][j], 1ll * (j + 1) * si[i][j] % mod);
            add(f[i][j], -sij[i][j]);

            add(s[i][j], f[i][j]);
            add(si[i][j], 1ll * i * f[i][j] % mod);
            add(sj[i][j], 1ll * j * f[i][j] % mod);
            add(sij[i][j], 1ll * i * j * f[i][j] % mod);

            add(ans, 1ll * f[i][j] * i % mod * j % mod * (n - i + 1) % mod * (m - j + 1) % mod);
        }
    cout << 1ll * ans * ifac[n * m] % mod * fac[k] % mod * fac[n * m - k] % mod << endl;
    return 0;
}

如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧

posted @ 2023-06-29 15:18  Morning_Glory  阅读(16)  评论(0编辑  收藏  举报
//