40 CF559C Gerald and Giant Chess 题解

CF559C Gerald and Giant Chess

题面

给定一个 \(H \times W\) 的棋盘,棋盘上只有 \(N\) 个格子是黑色的,其他格子都是白色

在棋盘左上角有一个卒,每一步可以向下或者向右移动一格,并且不能移动到黑色格子中。

求这个卒从左上角移动到右下角,一共有多少种可能的路线?

\(1 \le H,W \le 10^5, \ 1 \le N \le 2000\) 输出答案对 \(10^9 + 7\) 取模的结果即可

题解

棋盘上的白色格子很多,但是黑色格子只有 \(2000\) 个,所以我们考虑怎样利用黑色格子计数

这种计数类问题要做到不重不漏,要保证每一类情况是互斥的,不能有重合,并且能包含所有情况

为了方便,我们把右下角格子看做第 n + 1 个黑色格子

先将黑色格子按照横纵坐标排序,然后进行dp

\(f(i)\) 表示从左上角走到第 \(i\) 个黑色格子并且中间不经过其他黑色格子的方案数,初始状态 \(f[0] = 1\) ,目标状态 \(f[N + 1]\)

转移

\[f(i) = \binom {x_i - 1 + y_i - 1} {x_i - 1} - \sum_{j = 1}^{i - 1} f(j) \times \binom {x_i - x_j + y_i - y_j} {x_i - x_j} \]

\(j\) 满足 \(x_j \le x_i \and y_j \le y_i\)

时间复杂度为 \(O(n^2)\)

code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>

using namespace std;

typedef long long ll;

const int N = 2010, M = 2e5 + 10;
const int mod = 1e9 + 7;

int H, W, n;
pair <int, int> a[N];
ll f[N], fac[M], inv[M];

int pw (int a, int b) {
    ll res = 1, t = a;
    while (b) {
        if (b & 1) {
            res *= t;
            res %= mod;
        }
        t *= t;
        t %= mod;
        b >>= 1;
    }
    return res;
}

void init () {
    int mn = H + W;
    fac[0] = 1, inv[0] = 1;
    for (int i = 1; i <= mn; i ++) {
        fac[i] = fac[i - 1] * i % mod;
    }
    inv[mn] = pw (fac[mn], mod - 2);
    for (int i = mn - 1; i >= 1; i --) {
        inv[i] = inv[i + 1] * (i + 1) % mod;
    }
}

int calc (int x, int y) {
    if (y > x) return 0;
    return (ll)fac[x] * inv[y] % mod * inv[x - y] % mod;
}

int main () {

    cin >> H >> W >> n;
    init ();
    for (int i = 1; i <= n; i ++) {
        scanf ("%d%d", &a[i].first, &a[i].second);
    }
    sort (a + 1, a + 1 + n);
    a[n + 1] = {H, W};

    for (int i = 1; i <= n + 1; i ++) {
        f[i] = calc (a[i].first - 1 + a[i].second - 1, a[i].first - 1);
        for (int j = 1; j < i; j ++) {
            if (a[j].second > a[i].second) continue;
            f[i] -= f[j] * calc (a[i].first - a[j].first + a[i].second - a[j].second, a[i].first - a[j].first) % mod;
        }
        f[i] = (f[i] % mod + mod) % mod;
    }

    cout << f[n + 1] << endl;

    return 0;
}
posted @ 2025-10-09 21:19  michaele  阅读(7)  评论(0)    收藏  举报