Gerald and Giant Chess组合数容斥+dp

经典的走格子问题,从(1,1)到(n,m)的种类数,传统n²做法,f[i][j] = f[i][j - 1] + f[i - 1][j],但是这题数据比较大,组合数可以用费马小定理求,经典的组合数公式,2e5的组合数,预处理求即可,关键是怎么去掉那些不能走的格子的方案数。

传送门
Solution
考虑只有一个黑点情况,我们到这个黑点的种类数不能计算,减掉即可。多个同理,但是我们得保证计算去掉当前黑点,位于左上方的点,都得计算完毕,我们给他按照x,y升序排列,f[i]表示到i这个黑点可走的种类数,++k,把(n, m)当成最后一个点,最后的f[k]就是方案数。特别注意这个公式:(1,1)->(n, m)的种类数为C(n + m -2, n -1)
Code

#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <algorithm>
#define x first
#define y second
#define int long long
#define endl "\n"
#define pii pair<int, int>
#define RE(i,a,b) for(int i = a; i <= b; ++i)
using namespace std;
template <typename T> inline void read(T& t) {
    int f = 0, c = getchar();
    t = 0;
    while (!isdigit(c)) f |= c == '-', c = getchar();
    while (isdigit(c)) t = t * 10 + c - 48, c = getchar();
    if (f) t = -t;
}
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
int fac[N], inv[N];
struct node {
    int x, y;
    bool operator < (const node& rhs) const {
        return x == rhs.x ? y < rhs.y : x < rhs.x;
    }
} a[2010];
int n, m, k;
int f[N];
int qk(int a, int b) {
    int ans = 1;
    a %= mod;
    while(b) {
        if(b & 1) ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}
void init() {
    fac[0] = 1;
    for(int i = 1; i < N; i++)fac[i] = fac[i - 1] * i % mod;
    inv[N- 1] = qk(fac[N - 1], mod - 2);
    for(int i = N - 2; i >= 0; i--)inv[i] = (i + 1) * inv[i + 1] % mod;
}

int C(int a, int b) {
    if(b < 0 || b > a) return 0;
    return fac[a] * inv[a - b] % mod * inv[b] % mod;
}
signed main() {
    ios::sync_with_stdio(false), cin.tie(0);
    init();
    cin >> n >> m >> k;
    RE(i, 1, k) cin >> a[i].x >> a[i].y;
    a[++k] = {n, m};
    sort(a + 1, a + 1 + k);
    RE(i, 1, k) {
        f[i] = C(a[i].x + a[i].y - 2, a[i].x - 1);//计算到该点的种类数
        for(int j = 1; j < i; ++j) {
            if(a[j].x <= a[i].x && a[j].y <= a[i].y) {//如果完全在左上方,就挖掉这些种类数
                f[i] = (f[i] - f[j] * C(a[i].x - a[j].x + a[i].y - a[j].y, a[i].x - a[j].x) % mod + mod) % mod;
            }
        }
    }
    cout << f[k];
    return 0;
}
posted @ 2022-09-01 17:27  std&ice  阅读(45)  评论(0编辑  收藏  举报