Codeforces 559C Gerald and Giant Chess(组合数学+DP)
题目大意:求一个矩形网格,从左上角到右下角不经过黑点的路径数
知识点:
- 组合数取模,在膜不超过十的五次方时可以用Lucas算法简化,本题中mod=10e9+7,所以不需要Lucas,直接预处理阶乘,在求组合数还要会求出逆元
如果Cmn%p表示为Lucas(m,n,p) 如 果 C n m % p 表 示 为 L u c a s ( m , n , p )那么Cmn%p=Cm%pn%p∗Lucas(m/p,n/p,p)%p 那 么 C n m % p = C n % p m % p ∗ L u c a s ( m / p , n / p , p ) % p
3.AC代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long mod=1000000007;
struct node
{
long long x,y;
}point[2010];
bool cmp(node a,node b)
{
if(a.x==b.x)
return a.y<b.y;
return a.x<b.x;
}
long long dp[2010];
long long fac[200010];
void init()//预处理阶乘
{
fac[0]=1,fac[1]=1;
for(long long i=2;i<=200000;i++)
fac[i]=((fac[i-1]%mod)*(i%mod))%mod;
}
long long C(long long n,long long m)//求C(n,m)
{
long long ans=1,res=((fac[m]%mod)*(fac[n-m]%mod))%mod;
long long a=mod-2;
while(a)
{
if(a&1)
ans=((res%mod)*(ans%mod))%mod;
res=((res%mod)*(res%mod))%mod;
a=a>>1;
}
ans=((ans%mod)*(fac[n]%mod))%mod;
return ans;
}
int main()
{
long long h,w,n;
init();
while(~scanf("%lld%lld%lld",&h,&w,&n))
{
for(long long i=1;i<=n;i++)
scanf("%lld%lld",&point[i].x,&point[i].y);
point[n+1].x=h,point[n+1].y=w;
sort(point+1,point+n+1,cmp);
for(long long i=1;i<=n+1;i++)
{
dp[i]=C(point[i].x+point[i].y-2,point[i].x-1)%mod;
//printf("%lld\n",dp[i]);
for(long long j=1;j<i;j++)
{
if(point[j].x<=point[i].x&&point[j].y<=point[i].y)
{
dp[i]=((dp[i]-dp[j]*C(point[i].x-point[j].x+point[i].y-point[j].y,point[i].x-point[j].x))%mod+mod)%mod;
}
}
//.printf("%lld\n",dp[i]);
}
printf("%lld\n",dp[n+1]);
}
return 0;
}