[CF559C] Gerald and Giant Chess
Gerald and Giant Chess
题意:
给你一个 h × w h\times w h×w的网格和 n n n个黑点,问你从 ( 1 , 1 ) (1, 1) (1,1)到 ( h , w ) (h, w) (h,w)且不经过那 n n n个黑点的方案数,你只能向下或者向右走,答案对 1 0 9 + 7 10^9+7 109+7取模。
分析:
首先我们分析没有一个黑点的方案数,即我们只需要向下走 h − 1 h-1 h−1步,向右走 w − 1 w - 1 w−1步。那么也就是在这 h + w − 2 h + w - 2 h+w−2步中我们选择 h − 1 h - 1 h−1步向下走,即方案数为 C h + w − 2 h − 1 C_{h + w - 2}^{h - 1} Ch+w−2h−1。
然后我们排除掉经过那 n n n个黑点的方案数,这时我们可能会想到用容斥原理,即:
r e s = C h + w − 2 h − 1 − P 1 + P 2 − P 3 + . . . + ( − 1 ) n P n \large res = C_{h + w - 2}^{h - 1} - P_1 + P_2 - P_3 + ... + (-1)^nP_n res=Ch+w−2h−1−P1+P2−P3+...+(−1)nPn。
但是我们 n n n的范围是 n ≤ 2000 n \le 2000 n≤2000的,所以直接用容斥原理不可取。因为容斥原理的复杂度为 O ( 2 n ) O(2^n) O(2n)。
通过上面的分析我们可以进一步优化,我们设 d p i dp_i dpi表示从 ( 1 , 1 ) (1, 1) (1,1)走到第 i i i个黑点,且不经过其他黑点的方案数。
那么有: d p i = C x i + y i − 2 x i − 1 − ∑ j = 1 i − 1 d p i × C x i − x j + y i − y j x i − x j \large dp_i = C_{x_i + y_i - 2}^{x_i - 1} - \sum_{j = 1}^{i - 1}dp_i\times C_{xi - x_j + y_i - y_j}^{x_i - x_j} dpi=Cxi+yi−2xi−1−∑j=1i−1dpi×Cxi−xj+yi−yjxi−xj
不理解的可以画一下图,很直观。
然后我们这题就能写出来了,在这之前我们还要先把黑点进行排序,因为我们看这个 d p dp dp公式可以发现,转移方程和黑点的下标顺序有关。
我们将 ( h , w ) (h, w) (h,w)可以看作是第 n + 1 n + 1 n+1个黑点,所以代码如下:
#include #define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int MOD = 1e9 + 7;
const int maxn = 1e6 + 5;ll qpow(ll a, ll b, ll mod) {ll res = 1;while (b) {if (b & 1) res = res * a % mod;a = a * a % mod;b >>= 1;}return res;
}ll fac[maxn], inv[maxn];void init(int n) {fac[0] = 1;for (int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i % MOD;inv[n] = qpow(fac[n], MOD - 2, MOD);for (int i = n - 1; i >= 0; i--) inv[i] = inv[i + 1] * (i + 1) % MOD;
}ll C(int n, int m) {if (n < m) return 0;return fac[n] * inv[m] % MOD * inv[n - m] % MOD;
}PII p[maxn];
ll dp[maxn];int main() {int h, w, n;scanf("%d%d%d", &h, &w, &n);for (int i = 1; i <= n; i++) scanf("%d%d", &p[i].fi, &p[i].se);n++;p[n].fi = h, p[n].se = w;sort(p + 1, p + n + 1);init(max(h, w) << 1);for (int i = 1; i <= n; i++) {dp[i] = C(p[i].fi + p[i].se - 2, p[i].fi - 1);for (int j = 1; j < i; j++) {dp[i] = ((dp[i] - dp[j] * C(p[i].fi + p[i].se - p[j].fi - p[j].se, p[i].fi - p[j].fi) % MOD) % MOD + MOD) % MOD;}}printf("%lld\n", dp[n]);return 0;
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
