题解 AT1974 【[ARC058B] いろはちゃんとマス目 / Iroha and a Grid】

传送门

题意:

给出一个\(H \times W\)的矩阵,将左下角挖去一个\(A \times B\)的小矩阵,求从左上角走到右下角的方案数。
首先看好边界问题,实际上只走了\(H + W - 2\)步。

思路:

这道题第一眼看上去有点容斥的意思,考虑怎么求答案
如果没有小矩阵,那么方案数很显然是 \(C_{H + W - 2}^{H - 1}\),但是有了小矩阵,那么只需要把经过小矩阵的答案的贡献减去就好了。
再考虑怎么算经过小矩阵的方案数,首先暴力枚举一个位置\(i\)(小矩阵的上沿),即这条路线在该位置第一次经过小矩阵,此时一定是不合法的方案了,剩下的步数为\(W - i + A - 1\) 步(已经走了\(H - A + i - 1\)步)但是如果在走到\(i\)位置的时候如果继续向右走,答案就会和\(i + 1\)的位置重复,所以我们强制要求到达\(i\)位置之后向下走一步,然后继续走,当\(i\)为B的时候就不存在和\(i + 1\)重复的可能了,因此第\(B\)位置特殊处理,这样就可以得到答案:
\(C_{H + W - 2}^{H - 1} - \sum\limits_{i = 1}^{B - 1} C_{H - A + i - 1}^{H - A} \times C_{W - i + A - 2}^{W - i} - C_{H - A + B - 1}^{H - A} \times C_{W - B + A - 1}^{W - B}\)
代码实现:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
const int maxn = 2e6 + 50, mod = 1e9 + 7;
long long H, W, A, B;
long long jc[maxn], ny[maxn], jcny[maxn];
void init () {
	jc[1] = ny[1] = jcny[1] = jcny[0] = 1;
	long long a, b;
	for (register long long i = 2; i <= maxn - 5; ++i) {
		jc[i] = jc[i - 1] * i % mod;
		a = mod / i, b = mod % i;
		ny[i] = (-a * ny[b] % mod + mod) % mod;
		jcny[i] = jcny[i - 1] * ny[i] % mod;
	}
}
inline long long C (int a, int b) {
	if (a == 0 || b == 0 || a == b) return 1;
	return jc[a] * jcny[b] % mod * jcny[a - b] % mod;
}
long long ans;
signed main () {
	init();
	scanf ("%lld%lld%lld%lld", &H, &W, &A, &B);
	ans = C(H + W - 2, H - 1);
	for (register int i = 1; i < B; i++) {
		ans = ((ans - (C(H - A + i - 1, H - A) * C(W - i + A - 2, W - i) % mod)) % mod + mod) % mod;
	}
	ans = ans = ((ans - (C(H - A + B - 1, H - A) * C(W- B + A - 1, W - B) % mod)) % mod + mod) % mod;
	cout<<ans<<endl;
	return 0;
}
posted @ 2020-11-23 20:19  Blancа  阅读(87)  评论(2编辑  收藏  举报
哈哈,你打开了控制台,是想要看看我的秘密吗?
莫挨老子!