CF559C Gerald and Giant Chess

题意:

给定一个H*W的棋盘,棋盘上只有N个格子是黑色的,其他格子都是白色的。
在棋盘左上角有一个卒,每一步可以向右或者向下移动一格,并且不能移动到黑色格子中。求这个卒从左上角移动到右下角,一共有多少种可能的路线。

输入格式

第1行:3个正整数h,w,n(1≤h,w≤10^5,1≤n≤2000)
接下来n行,第i+1行包含两个整数ri,ci即黑色格子的坐标

输出格式

输出一个整数,即总的方案数。

样例

样例输入

100 100 3
15 16
16 15
99 88

样例输出

545732279

#include<bits/stdc++.h>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2010;
const int mod=1e9+7;
typedef long long LL;
struct Point
{
int x,y;
bool operator <(const Point &A)const{
if(x!=A.x)return x<A.x;
else return y<A.y;
}
}P[N];
LL fac[2*100010],inv[2*100010];
LL quickpow(LL x,int n)
{
LL ret=1;
while(n)
{
if(n&1){
ret=ret*x%mod;
}
x=x*x%mod;
n>>=1;
}
return ret;
}
void init(int n)
{
fac[0]=1;
for(int i=1;i<=n;i++){
fac[i]=fac[i-1]*(LL)i%mod;
inv[i]=quickpow(fac[i],mod-2);
}
inv[0]=inv[1];
}
LL Cal(int x,int y)
{
LL ret=fac[x+y]*inv[x]%mod*inv[y]%mod;
return ret;
}
LL sum[N];
int main(){
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i=0;i<k;i++)
{
int u,v;
scanf("%d%d",&u,&v);
u--;v--;
P[i].x=u;P[i].y=v;
}
sort(P,P+k);
P[k].x=n-1;
P[k].y=m-1;
init(n+m);
for(int i=0;i<=k;i++)
{
sum[i]=Cal(P[i].x,P[i].y);
// cout<<i<<" "<<sum[i]<<" at first"<<endl;
for(int j=0;j<i;j++)
{
if(P[j].x<=P[i].x&&P[j].y<=P[i].y)
{
sum[i]=(sum[i]-sum[j]*Cal(P[i].x-P[j].x,P[i].y-P[j].y)%mod)%mod;
//if(sum[i]<=0)sum[i]=(sum[i]+mod)%mod;
}
}
// cout<<i<<" "<<sum[i]<<" at last"<<endl;
}
printf("%lld ",(sum[k]+mod)%mod);
return 0;
}

/*
6 6 3
2 2
3 4
4 5
按题意,将坐标都减去1
对于第一个黑点(1,1),走到它有C(1+1,1)=2种方式
对于第二个黑点(3,4),从(0,0)走到它有C(2+3,2)=10种方式,从1号黑色点走到它有3种方式
于是不经过1号黑色点,从出发点走到二号黑色点有10-2*3=4种方式
同理算出三号点,有7种方式
将结束点也当成黑色点,共有c(5+5,5)=252种方式
ans=252-c(5-1+5-1,5-1)*2-C(5-2+5-3,5-3)*4-c(5-3+5-4,5-3)*7
=252-140-40-21=51
*/

*/

  

原文地址:https://www.cnblogs.com/cutemush/p/11904865.html