[CodeForces][计数DP] Gerald and Giant Chess

题面

// 首先看范围不太可直接暴力解
// 考虑 f[i] 为经过第 i 个黑点的方案数,
// 直接计算比较难算,可以从总方案减去不合法方案。
// f[i] = C(xi-1, xi+yi-2) - sum(f[j] * C(xi-xj, xi+yi-xj+yj));

# include <iostream>
# include <cstdio>
# include <algorithm>
# define LL long long
# define MAXN 300005

const LL MOD = 1e9+7;

struct point{
	int x, y;
}p[MAXN];
LL inv[MAXN], fac[MAXN];
LL f[MAXN];

bool CmpP(point x, point y){
	return x.x == y.x ? x.y < y.y : x.x < y.x;
}

LL QPow(LL x, LL y){
	LL ans = 1, base = x % MOD;
	while(y){
		if(y & 1){
			(ans *= base) %= MOD;
		}
		(base *= base) %= MOD;
		y >>= 1;
	}
	return ans;
}

LL Combine(LL m, LL n){
	if(m > n){
		return 0;
	}
	return (((fac[n] * inv[n-m]) % MOD) * inv[m]) % MOD;
}

int main(){
	int h, w, n;
	scanf("%d%d%d", &h, &w, &n);

	for(int i = 1; i <= n; i++){
		scanf("%d%d", &p[i].x, &p[i].y);
	}
	p[++n] = (point){h, w};

	std::sort(p+1, p+n+1, CmpP);

	fac[0] = inv[0] = 1;
	for(int i = 1; i <= MAXN; i++){
		fac[i] = (fac[i-1]*i) % MOD;
		inv[i] = QPow(fac[i], MOD-2);
	}

	for(int i = 1; i <= n; i++){
		f[i] = Combine(p[i].x-1, p[i].x+p[i].y-2);
	}

	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= i-1; j++){
			if(p[j].x > p[i].x || p[j].y > p[i].y){
				continue;
			}

			f[i] -= f[j]*Combine(p[i].x-p[j].x, p[i].x+p[i].y-p[j].x-p[j].y);
			(f[i] += MOD) %= MOD;
		}
	}

	printf("%lld", (f[n]+MOD)%MOD);

	return 0;
}
posted @ 2020-09-05 20:21  ChPu437  阅读(117)  评论(0编辑  收藏  举报