组合数学 + 容斥
首先考虑一下不经过障碍物的情况,从$(1, 1)$到$(n, m)$相当于在$n +m - 2$步中选出$m - 1$步往下走,方案数$\binom{n + m - 2}{m - 1}$。
再考虑一下只有一个障碍物的情况,假设这个障碍物$(x, y)$,那么总的方案数是$\binom{n + m - 2}{m - 1} - \binom{n + m - x - y}{m - y} * \binom{x + y - 2}{y - 1}$。
那么有多个障碍物的情况怎么办呢?
考虑到一个障碍物$(x, y)$只会对$(1, 1) ~ (x, y)$之内的格子产生影响,所以我们可以考虑从容斥,这样子就得到一个类似于dp的东西。
我脑子一抽就写了个反的
设$f_{i}$表示从$(n, m)$走到第$i$个障碍物的方案数,那么有
$f_{i} = \binom{n + m - x - y}{m - y}$
$f_{i} -= f_{j} * \binom{x' - x + y' - y}{y' - y}$ $(j != i), x \leq x', y \leq y'$(假设$i$的坐标是$(x, y)$,$j$的坐标是$(x', y')$)。
把所有障碍物排序一遍就很好写了。
组合数可以$O(n)$预处理。
时间复杂度$(n^{2})$。
Code:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int N = 2005; const int M = 2e5 + 5; const ll P = 1e9 + 7; int n, m, K; ll fac[M], inv[M], f[N]; struct Node { int x, y; } a[N]; bool cmp(const Node &u, const Node &v) { if(u.x == v.x) return u.y < v.y; else return u.x < v.x; } inline void read(int &X) { X = 0; char ch = 0; int op = 1; for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') op = -1; for(; ch >= '0' && ch <= '9'; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } inline ll pow(ll x, ll y) { ll res = 1LL; for(; y > 0; y >>= 1) { if(y & 1) res = res * x % P; x = x * x % P; } return res; } inline ll getC(int x, int y) { return fac[x] * inv[y] % P * inv[x - y] % P; } int main() { read(n), read(m), read(K); for(int i = fac[0] = 1; i <= n + m; i++) fac[i] = 1LL * fac[i - 1] * i % P; inv[n + m] = pow(fac[n + m], P - 2); for(int i = n + m - 1; i >= 0; i--) inv[i] = 1LL * inv[i + 1] * (i + 1) % P; // printf("%lld\n", getC(7, 3)); for(int i = 1; i <= K; i++) read(a[i].x), read(a[i].y); // a[++K].x = 1, a[K].y = 1; sort(a + 1, a + 1 + K, cmp); ll ans = getC(m + n - 2, m - 1); for(int i = K; i >= 1; i--) { f[i] = (f[i] + getC(m + n - a[i].x - a[i].y, m - a[i].y) + P) % P; for(int j = i + 1; j <= K; j++) if(a[j].x >= a[i].x && a[j].y >= a[i].y) f[i] = (f[i] - f[j] * getC(a[j].x - a[i].x + a[j].y - a[i].y, a[j].y - a[i].y) % P + P) % P; ans = (ans - f[i] * getC(a[i].x + a[i].y - 2, a[i].y - 1) % P + P) % P; } printf("%lld\n", ans); return 0; }