Link
Solve
有一个结论,对于一个(W)和(H)的白色方格,从((1,1))到((H,W))的方案数是(C_{H+W-2}^{H-1})
直接考虑不能走黑色的比较难,于是想到容斥一下,把总的方案数-经过黑点的方案数=不走黑色的方案数
因为黑点的数比较少,于是用黑点来(DP),先把黑点按照(x)排序
定义(F[i])表示从左上角走到(i)这个黑色节点的位置,不经过其他黑点的方案数
由于总的方案数-经过至少一个黑点的方案数=不经过其他黑点的方案数
经过至少一个黑点的方案数=不经过白点到一个黑点,后面乱走,枚举每个满足的黑点,把答案累计起来就好了
所以转移方程就退出来了
[F[i]=C_{x_i-1+y_i-1}^{x_i-1}-sum_{j=0}^{i-1}F[j]ast C_{x_i-x_j+y_i-y_j}^{x_i-x_j}
]
其中(x_i≥x_j,y_i≥y_j)
#include<bits/stdc++.h>
using namespace std;
const int maxn=2005,TT=1000000007;
typedef long long LL;
int H,W,N;
pair<int,int> a[maxn];
LL jc[200005],jcinv[200005],F[maxn];
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
LL fast_pow(LL a,LL b){
LL s=1,w=a;
while(b){
if(b&1)s=s*w%TT;
w=w*w%TT;
b>>=1;
}
return s;
}
LL C(LL x,LL y){
return jc[x]*jcinv[y]%TT*jcinv[x-y]%TT;
}
int main(){
jc[0]=1;jcinv[0]=1;
for(int i=1;i<=200000;i++){
jc[i]=jc[i-1]*i%TT;
jcinv[i]=fast_pow(jc[i],TT-2);
}
H=read();W=read();N=read();
for(int i=1;i<=N;i++)a[i].first=read(),a[i].second=read();
sort(a+1,a+1+N);
a[N+1].first=H,a[N+1].second=W;
for(int i=1;i<=N+1;i++){
F[i]=C(a[i].first+a[i].second-2,a[i].first-1);
for(int j=1;j<i;j++){
if(a[j].first>a[i].first||a[j].second>a[i].second)continue;
F[i]=(F[i]-F[j]*C(a[i].first+a[i].second-a[j].first-a[j].second,a[i].first-a[j].first)%TT+TT)%TT;
}
}
printf("%lld
",(F[N+1]+TT)%TT);
return 0;
}