给一个棋盘,一些黑色格子不可以走,问从左上走到右下的方法数。
http://codeforces.com/problemset/problem/559/C
http://codeforces.com/blog/entry/19237 题解。
dp[i]表示从(1, 1) 到第i个黑色格子,且不经过第1,2,..i-1个格子的方法数.
dp[i]我们可以这么算
首先随便走的话答案是C(m, n)减去其中不合法的路径,不合法的路径我们分为 第一个经过的黑格子是第j(j < i)个的,这就等于 dp[j] * (从第j个格子到第i个格子的方法数,直接组合数),这样便算出了dp[i];
我们把终点当做最后一个黑格子就可以了。
预处理阶乘,算组合数用逆元。
贴个别人的代码
#include<cstdio>
#include<utility>
#include<algorithm>
using namespace std;
const long long mod=1000000007;
typedef pair<int,int> P;
int H,W,N;
P ps[2020];
long long dp[2020];
long long fact[200200];
long long ifact[200200];
long long ex(long long a,long long e)
{
if(e==0) return 1;
long long res=ex(a,e/2);
res*=res;
res%=mod;
if(e%2==1) res*=a;
res%=mod;
return res;
}
long long inv(long long a)
{
return ex(a,mod-2);
}
long long C(int h,int w)
{
if(h<0||w<0) return 0;
long long res=fact[h+w];
res*=ifact[h];
res%=mod;
res*=ifact[w];
res%=mod;
return res;
}
long long solve()
{
ps[N]=P(H,W);
N++;
sort(ps,ps+N);
for(int i=0; i<N; i++)
{
dp[i]=C(ps[i].first,ps[i].second);
for(int j=0; j<i; j++)
{
int h=ps[i].first-ps[j].first;
int w=ps[i].second-ps[j].second;
long long tmp=C(h,w);
tmp*=dp[j];
tmp%=mod;
dp[i]-=tmp;
dp[i]%=mod;
}
}
dp[N-1]+=mod;
dp[N-1]%=mod;
return dp[N-1];
}
int main()
{
scanf("%d%d%d",&H,&W,&N);
H--;
W--;
for(int i=0; i<N; i++)
{
int h,w;
scanf("%d%d",&h,&w);
h--;
w--;
ps[i]=P(h,w);
}
fact[0]=1;
ifact[0]=1;
for(int i=1; i<200200; i++)
{
fact[i]=fact[i-1]*i;
fact[i]%=mod;
ifact[i]=inv(fact[i]);
}
long long ans=solve();
printf("%d\n",(int)ans);
return 0;
}