大意:
从左上角移动到右下角,其中有k个黑块不能走,问方案数
思路:
从左上角到有下角,方案为(C_{n+m}^{n}),先将黑点从左上到右下排个序,(dp[i])代表走到当前黑点的方案数,它可以根据左上方的(dp[i])转移过来,(dp[i]=C_{x_i+y_i}^{x_i}-sum{dp[j]*C_{x_j+y_j}^{x_j}}),最后把右下角作为一个黑块一起求得即可
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL N = 1e6 + 5,mod = 1e9+7;
LL n, m,k,dp[N];
LL fact[N], infact[N];
LL qmi(LL a, LL k, LL p) {
LL res = 1;
while (k) {
if (k & 1) res = res * a % p;
k >>= 1;
a = a * a % p;
}
return res;
}
// 预处理
void init() {
fact[0] = infact[0] = 1;
for (int i = 1; i < N; ++i) {
fact[i] = (LL)fact[i - 1] * i % mod;
infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
}
}
LL c(int a,int b){
return (LL)fact[a] * infact[b] % mod * infact[a - b] % mod;
}
struct node{
int x, y;
} h[3000];
bool cmp(node a,node b){
return a.x < b.x || (a.x == b.x && a.y < b.y);
}
int main(){
init();
cin >> n >> m >> k;
for (int i = 0; i < k;i++){
dp[i] = 0;
cin >> h[i].x >> h[i].y;
}
h[k].x = n, h[k].y = m;
dp[k] = 0;
sort(h,h+k+1,cmp);
for (int i = 0; i <= k;i++){
dp[i] = c(h[i].x + h[i].y - 2, h[i].x - 1);
for (int j = 0; j < i;j++){
if(h[i].x>=h[j].x&&h[i].y>=h[j].y)
dp[i] = (dp[i] - dp[j] * c(h[i].x + h[i].y - h[j].y - h[j].x, h[i].x - h[j].x) % mod + mod) % mod;
}
}
cout << dp[k] << endl;
return 0;
}