題目
分析
正整數 滿足 ,則 的取值方案數爲 。證明:將問題轉化爲構造一個序列 表示 中每個數在 中出現了多少次,則 與 一一對應,我們只需要求 的取值方案數, 需滿足的條件是 且 ,插空法得 的方案數爲 。
然後枚舉 的高度計算方案數即可。
錯因
- 想到 轉化爲 的時候考試僅剩十幾分鍾了,推出 的時候還有 3 分鐘考試結束;
- 預處理階乘的時候要處理到 而不是 (最後一分鐘過了第一個樣例第二個樣例出 0,如果多 3 分鐘就能發現這個問題但是沒有時間了,導致 100 pts 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;
}