Gerald and Giant Chess

CF

洛咕

题意:给定一个\(H*W(H,W<=1e5)\)的棋盘,棋盘上只有\(N(N<=2000)\)个格子是黑色的,其他格子都是白色的.在棋盘左上角有一个卒,每一步可以向右或者向下移动一格,并且不能移动到黑色格子中.求这个卒从左上角移动到右下角,一共有多少种可能的路线.答案对\(1e9+7\)取模.

分析:这种题目直接算肯定不好算,因为黑色格子远远少于白色格子,考虑\(ans=\)所有方案-不合法方案.

首先从左上角走到右下角的总方案数为\(C_{H-1+W-1}^{H-1}\).

将n个黑色格子按照横坐标从小到大排序.设\(f[i]\)表示从左上角走到(排序后的)第i个黑色格子并且途中不经过其它黑色格子的方案数.

\(f[i]=C_{x_i-1+y_i-1}^{x_i-1}-\sum_{j=0}^{i-1}f[j]*C_{x_i-x_j+y_i-y_j}^{x_i-x_j}\)

很好理解,用到i的所有方案数减去j到i的所有方案数(因为j也是黑色格子,所以j到i的所有方案都是不合法的),剩下的就是合法的到i的方案数了.

我们把右下角看作第n+1个黑色格子,于是\(ans=f[n+1]\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=200005;
const int mod=1e9+7;
ll jc[N],inv[N],f[N];
struct ppx{
	int x,y;
}a[2005];
inline bool cmp(const ppx &x,const ppx &y){return x.x==y.x?x.y<y.y:x.x<y.x;}
inline ll ksm(int a,int b){
	ll cnt=1;
	while(b){
		if(b&1)cnt=(1ll*cnt*a)%mod;
		a=(1ll*a*a)%mod;
		b>>=1;
	}
	return cnt;
}
inline ll C(int n,int m){return 1ll*jc[n]*inv[m]%mod*inv[n-m]%mod;}
int main(){
	jc[0]=1;inv[0]=1;
	for(int i=1;i<=200000;++i){
		jc[i]=(jc[i-1]*i)%mod;
		inv[i]=ksm(jc[i],mod-2);
	}
	int h=read(),w=read(),n=read();
	for(int i=1;i<=n;++i)a[i].x=read(),a[i].y=read();
	sort(a+1,a+n+1,cmp);a[n+1].x=h;a[n+1].y=w;
	for(int i=1;i<=n+1;++i){
		f[i]=C(a[i].x+a[i].y-2,a[i].x-1);
		for(int j=1;j<i;++j)
			f[i]=(f[i]-1ll*f[j]*C(a[i].x-a[j].x+a[i].y-a[j].y,a[i].x-a[j].x))%mod;
	}
	printf("%lld\n",(f[n+1]+mod)%mod);
	return 0;
}

posted on 2019-06-18 22:18  PPXppx  阅读(247)  评论(0编辑  收藏  举报