• 题解-CF559C


    一道计数类dp题。

    直接dp的复杂度是 (O(hw)) 的显然不行,发现黑格的数量很少,我们尝试从反面入手。首先所有的情况是 (C_{h+w-2}^{h-1})。就是在总共要走的 (h+w-2) 步中选择 (h-1) 向下的方案数。然后减去至少经过一个黑点的方案数。这可以容斥但是复杂度是 (O(2^n)) 还不如暴力,我们考虑用计数dp。

    首先我们要找到一个基准点,可以是第一次经过的黑点。这样我们不关心后面怎么走,和前面的公式一样。现在我们考虑怎么不经过其他黑点走到当前黑点,我们发现这其实就是个子问题,用它前面的黑点更新就好了。实现的时候需要排序,保证前面的已经算出答案。

    还有一个细节就是我们可以再新添一个黑点 ((h,w)) 这样减少代码量。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod = 1e9 + 7;
    struct point{
    	int x, y;
    	friend bool operator < (point a, point b) {
    		if (a.x == b.x) return a.y < b.y;
    		return a.x < b.x;
    		
    	}
    }p[2010];
    int n, m, k;
    ll dp[2010], fac[200010], ifac[200010], inv[200010];
    ll C(ll x, ll y) {
    	if (x < 0 || y < 0 || x < y) return 0;
    	return fac[x] * ifac[x - y] % mod * ifac[y] % mod;
    }
    int main() {
    	scanf("%d%d%d", &n, &m, &k);
    	fac[0] = ifac[0] = fac[1] = ifac[1] = inv[1] = 1;
    	for (int i = 2; i <= n + m; i++) inv[i] = (mod - mod / i) * inv[mod % i] % mod, fac[i] = fac[i - 1] * i % mod, ifac[i] = ifac[i - 1] * inv[i] % mod;
    	for (int i = 1; i <= k; i++) scanf("%d%d", &p[i].x, &p[i].y);
    	sort(p + 1, p + 1 + k);
    	if (p[k].x == n && p[k].y == m) puts("0");
    	else {
    		p[++k].x = n;
    		p[k].y = m;
    		for (int i = 1; i <= k; i++) {
    			dp[i] = C(p[i].x + p[i].y - 2, p[i].x - 1);
    			for (int j = 1; j < i; j++) {
    				if (p[j].y <= p[i].y) {
    					dp[i] = ((dp[i] - dp[j] * C(p[i].x - p[j].x + p[i].y - p[j].y, p[i].x - p[j].x) % mod) % mod + mod) % mod;
    				}
    			}
    		}
    		printf("%lld
    ", (dp[k] + mod) % mod);
    	}
    	return 0;
    }
  • 相关阅读:
    es进行聚合操作时提示Fielddata is disabled on text fields by default
    es基本操作
    maven项目修改项目名
    Linux命令整理
    CentOS 安装git
    Linux命令
    纵表转横表
    Row_Number() over()
    事件冒泡/捕获
    js获取参数 解决乱码
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/15440313.html
Copyright © 2020-2023  润新知