[NOI Online #2 入门组] 建设城市(组合数学) | 错题本

    技术2025-09-14  36

    文章目录

    题目分析错因代码

    题目

    [NOI Online #2 入门组] 建设城市

    分析

    正整数 x 1 , x 2 , ⋯   , x n x_1, x_2, \cdots, x_n x1,x2,,xn 满足 1 ≤ x 1 ≤ x 2 ≤ ⋯ ≤ x n ≤ r 1 \leq x_1 \leq x_2 \leq \cdots \leq x_n \leq r 1x1x2xnr,则 x 1 , x 2 , ⋯   , x n x_1, x_2, \cdots, x_n x1,x2,,xn 的取值方案数为 C n + r − 1 r − 1 C_{n + r - 1}^{r - 1} Cn+r1r1。证明:将问题转化为构造一个序列 k 1 , k 2 , ⋯   , k r k_1, k_2, \cdots, k_r k1,k2,,kr 表示 [ 1 , r ] [1, r] [1,r] 中每个数在 x x x 中出现了多少次,则 k k k x x x 一一对应,我们只需要求 k k k 的取值方案数, k k k 需满足的条件是 k 1 + k 2 + ⋯ + k r = n k_1 + k_2 + \cdots + k_r = n k1+k2++kr=n k 1 , k 2 , ⋯   , k r ∈ [ 0 , n ] k_1, k_2, \cdots, k_r \in [0, n] k1,k2,,kr[0,n],插空法得 k k k 的方案数为 C n + r − 1 r − 1 C_{n + r - 1}^{r - 1} Cn+r1r1

    然后枚举 x , y x, y x,y 的高度计算方案数即可。

    错因

    想到 x x x 转化为 k k k 的时候考试仅剩十几分钟了,推出 C n + r − 1 r − 1 C_{n + r - 1}^{r - 1} Cn+r1r1 的时候还有 3 分钟考试结束;预处理阶乘的时候要处理到 m + n m + n m+n 而不是 n n n(最后一分钟过了第一个样例第二个样例出 0,如果多 3 分钟就能发现这个问题但是没有时间了,导致 100 pts → \to 0 pts);

    代码

    #include <algorithm> #include <cstring> #include <cstdio> #include <set> const int MOD = 998244353; const int MAXN = 100000; int M, N, X, Y; int Fac[2 * MAXN + 5], Inv[2 * MAXN + 5]; inline int Mul(const int &x, const int &y) { return (long long)x * y % MOD; } inline int Add(int x, const int &y) { x += y; if (x >= MOD) x -= MOD; return x; } int Pow(int x, int y) { int ret = 1; while (y) { if (y & 1) ret = Mul(ret, x); x = Mul(x, x); y >>= 1; } return ret; } int C(int n, int m) { return Mul(Fac[n], Mul(Inv[m], Inv[n - m])); } int Cal(int rgt, int n) { return C(n + rgt - 1, rgt - 1); } int main() { scanf("%d%d%d%d", &M, &N, &X, &Y); Fac[0] = 1; for (int i = 1; i <= M + N; i++) Fac[i] = Mul(Fac[i - 1], i); Inv[M + N] = Pow(Fac[M + N], MOD - 2); for (int i = M + N - 1; i >= 0; i--) Inv[i] = Mul(Inv[i + 1], i + 1); if (X > N) { int tmp = 2 * N - Y + 1; Y = 2 * N - X + 1; X = tmp; } // 通过这个处理把问题分成两类: 1 <= x < y <= n; 1 <= x <= n < y <= 2n if (Y <= N) { int Ans = 0, R = Cal(M, N); for (int i = 1; i <= M; i++) Ans = Add(Ans, Mul(R, Mul(Cal(i, X - 1), Cal(M - i + 1, N - Y)))); printf("%d", Ans); } else { int Ans = 0; for (int i = 1; i <= M; i++) { // printf("%d %d %d %d\n", Cal(i, X - 1), Cal(M - i + 1, N - X), Cal(i, 2 * N - Y), Cal(M - i + 1, Y - N - 1)); Ans = Add(Ans, Mul(Mul(Cal(i, X - 1), Cal(M - i + 1, N - X)), Mul(Cal(i, 2 * N - Y), Cal(M - i + 1, Y - N - 1)))); } printf("%d", Ans); } return 0; }
    Processed: 0.013, SQL: 9