一开始想用容斥原理 。。后来发现有些地方处理有些麻烦。。。
用dp的话,dp[i]并表示 从起点到 障碍i 所有的合法路径数
hint: 从起点到点 x,y的所有路径方案为 C(x-1+y-1,x-1) (要减一是因为本题是格点)
那么 对点i,把所有在点i的左上方的点称为j
dp[i]= C(x-1+y-1,x-1);
对所有j点:dp[i]-=dp[j]*get_dis(i,j)
把第q+1个点设为(n,m)即可
取组合要用到费马小定理,预处理好阶乘
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
__int64 dp[2005] ;
__int64 mod=1e9+7;
__int64 fast_m(__int64 a,__int64 b)
{
__int64 x,ans=1;
x=a;
while(b)
{
if (b&1)
ans=(ans*x)%mod;
x=(x*x)%mod;
b/=2;
}
return ans;
}
__int64 fac[200010];
inline __int64 cal(__int64 x,__int64 y)
{
return (fac[x]*fast_m(fac[y]*fac[x-y]%mod,mod-2))%mod;
}
struct node
{
__int64 x,y;
};
node tm[2005];
bool cmp(node &a,node &b)
{
if (a.x!=b.x)
return a.x<b.x;
else
return a.y<b.y;
}
int main()
{
__int64 x,y,i,j;
__int64 n,m,q;
scanf("%I64d%I64d%I64d",&n,&m,&q);
fac[0]=1;
for( i=1;i<=2e5;i++)
fac[i]=fac[i-1]*i%mod;
for (i=1;i<=q;i++)
{
scanf("%I64d%I64d",&tm[i].x,&tm[i].y);
}
sort(tm+1,tm+1+q,cmp);
tm[q+1].x=n;
tm[q+1].y=m;
__int64 add=0;
for (i=1;i<=q+1;i++)
{
dp[i]=cal(tm[i].x+tm[i].y-2,tm[i].x-1);
for (j=1;j<i;j++)
{
if (tm[j].x<=tm[i].x&&tm[j].y<=tm[i].y)
{
dp[i]= dp[i]-cal(tm[i].x+tm[i].y-tm[j].x-tm[j].y,tm[i].y-tm[j].y)*(dp[j]) %mod;
dp[i]=(dp[i]+mod)%mod;
}
}
}
__int64 ans=dp[q+1];
while(ans<0)
ans+=mod;
printf("%I64d\n",(ans) %mod);
return 0;
}