CF559C Gerald and Giant Chess 题解

Link

CF559C Gerald and Giant Chess

Solve

有一个结论,对于一个(W)(H)的白色方格,从((1,1))((H,W))的方案数是(C_{H+W-2}^{H-1})

直接考虑不能走黑色的比较难,于是想到容斥一下,把总的方案数-经过黑点的方案数=不走黑色的方案数

因为黑点的数比较少,于是用黑点来(DP),先把黑点按照(x)排序

定义(F[i])表示从左上角走到(i)这个黑色节点的位置,不经过其他黑点的方案数

由于总的方案数-经过至少一个黑点的方案数=不经过其他黑点的方案数

经过至少一个黑点的方案数=不经过白点到一个黑点,后面乱走,枚举每个满足的黑点,把答案累计起来就好了

所以转移方程就退出来了

[F[i]=C_{x_i-1+y_i-1}^{x_i-1}-sum_{j=0}^{i-1}F[j]ast C_{x_i-x_j+y_i-y_j}^{x_i-x_j} ]

其中(x_i≥x_j,y_i≥y_j)

#include<bits/stdc++.h>
using namespace std;
const int maxn=2005,TT=1000000007;
typedef long long LL;
int H,W,N;
pair<int,int> a[maxn];
LL jc[200005],jcinv[200005],F[maxn];
inline int read(){
	int ret=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
	while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
	return ret*f;
}
LL fast_pow(LL a,LL b){
	LL s=1,w=a;
	while(b){
		if(b&1)s=s*w%TT;
		w=w*w%TT;
		b>>=1;
	}
	return s;
}
LL C(LL x,LL y){
	return jc[x]*jcinv[y]%TT*jcinv[x-y]%TT;
}
int main(){
	jc[0]=1;jcinv[0]=1;
	for(int i=1;i<=200000;i++){
		jc[i]=jc[i-1]*i%TT;
		jcinv[i]=fast_pow(jc[i],TT-2);
	}
	H=read();W=read();N=read();
	for(int i=1;i<=N;i++)a[i].first=read(),a[i].second=read();
	sort(a+1,a+1+N);
	a[N+1].first=H,a[N+1].second=W;
	for(int i=1;i<=N+1;i++){
		F[i]=C(a[i].first+a[i].second-2,a[i].first-1);
		for(int j=1;j<i;j++){
			if(a[j].first>a[i].first||a[j].second>a[i].second)continue;
			F[i]=(F[i]-F[j]*C(a[i].first+a[i].second-a[j].first-a[j].second,a[i].first-a[j].first)%TT+TT)%TT;
		}
	}
	printf("%lld
",(F[N+1]+TT)%TT);
	return 0;
}
原文地址:https://www.cnblogs.com/martian148/p/14077930.html