题意:
从左上角走到右下角,每走一步只可以往下或者往右,其中有一些不可以走的点(黑点),问有多少种方案。
思路:
看了别人的blog,这不就是一个原题么。。。
知道两个点,原来直接求组合数就可以得到它们的方案数,这个倒是才知道。
http://blog.csdn.net/popoqqq/article/details/46121519
code:
#include <bits/stdc++.h>
using namespace std;
const int N = 2005;
const int M = 2e5+5;
const int MOD = 1e9+7;
typedef long long LL;
struct PP {
int x, y;
bool operator < (const PP &cmp) const {
if(x == cmp.x) return y < cmp.y;
return x < cmp.x;
}
}a[N];
int h, w, n;
LL dp[N];
LL ny[M], jc[M];
/*
LL exgcd(LL a, LL b, LL &x, LL &y) {
if(!b) {
x = 1, y = 0;
return a;
}
LL ans = exgcd(b, a%b, y, x);
y -= a/b*x;
return ans;
}
*/
LL mypow(LL a, int n) {
LL ret = 1;
while(n) {
if(n&1) ret = ret*a%MOD;
n >>= 1;
a = a*a%MOD;
}
return ret;
}
void solve() {
/*
jc[0] = 1;
for(int i = 1;i < M; i++) jc[i] = jc[i-1]*i%MOD;
LL tmp, x, y;
for(int i = 0;i < M; i++) {
tmp = exgcd(jc[i], MOD, x, y);
x = (x%MOD+MOD)%MOD;
ny[i] = x;
//if(ny[i]*jc[i] % MOD != 1) cout<<"??"<<endl;
}
*/
jc[0] = 1;
for(int i = 1;i < M; i++) jc[i] = jc[i-1]*i%MOD;
for(int i = 0;i < M; i++) ny[i] = mypow(jc[i], MOD-2);
a[n++] = (PP){h-1, w-1};
sort(a, a+n);
//dp[0] = 1;
for(int i = 0;i < n; i++) {
int t1 = a[i].x+a[i].y, t2 = a[i].x;
dp[i] = jc[t1]*ny[t2]%MOD*ny[t1-t2]%MOD;
for(int j = 0;j < i; j++) {
int t1 = (a[i].x-a[j].x)+(a[i].y-a[j].y),
t2 = a[i].y-a[j].y;
if(t2 < 0) continue;
LL tmp = jc[t1]*ny[t2]%MOD*ny[t1-t2]%MOD*dp[j]%MOD;
dp[i] = (dp[i]-tmp)%MOD;
if(dp[i] < 0) dp[i] = (dp[i]+MOD)%MOD;
}
}
printf("%I64d\n", dp[n-1]);
}
int main() {
scanf("%d%d%d", &h, &w, &n);
for(int i = 0;i < n; i++) {
scanf("%d%d", &a[i].x, &a[i].y);
a[i].x--, a[i].y--;
}
solve();
return 0;
}