• CF559C Gerald and Giant Chess


    组合数学 + 容斥

    首先考虑一下不经过障碍物的情况,从$(1, 1)$到$(n, m)$相当于在$n +m - 2$步中选出$m - 1$步往下走,方案数$inom{n + m - 2}{m - 1}$。

    再考虑一下只有一个障碍物的情况,假设这个障碍物$(x, y)$,那么总的方案数是$inom{n + m - 2}{m - 1} - inom{n + m - x - y}{m - y} * inom{x + y - 2}{y - 1}$。

    那么有多个障碍物的情况怎么办呢?

    考虑到一个障碍物$(x, y)$只会对$(1, 1) ~ (x, y)$之内的格子产生影响,所以我们可以考虑从容斥,这样子就得到一个类似于dp的东西。

    我脑子一抽就写了个反的

    设$f_{i}$表示从$(n, m)$走到第$i$个障碍物的方案数,那么有

      $f_{i} = inom{n + m - x - y}{m - y}$ 

      $f_{i} -= f_{j} * inom{x' - x + y' - y}{y' - y}$   $(j != i), x leq x', y leq y'$(假设$i$的坐标是$(x, y)$,$j$的坐标是$(x', y')$)。

    把所有障碍物排序一遍就很好写了。

    组合数可以$O(n)$预处理。

    时间复杂度$(n^{2})$。

    Code:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    
    const int N = 2005;
    const int M = 2e5 + 5;
    const ll P = 1e9 + 7;
    
    int n, m, K;
    ll fac[M], inv[M], f[N];
    
    struct Node {
        int x, y;
    } a[N];
    
    bool cmp(const Node &u, const Node &v) {
        if(u.x == v.x) return u.y < v.y;
        else return u.x < v.x;
    }
    
    inline void read(int &X) {
        X = 0; char ch = 0; int op = 1;
        for(; ch > '9' || ch < '0'; ch = getchar())
            if(ch == '-') op = -1;
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }
    
    inline ll pow(ll x, ll y) {
        ll res = 1LL;
        for(; y > 0; y >>= 1) {
            if(y & 1) res = res * x % P;
            x = x * x % P;
        }
        return res;
    }
    
    inline ll getC(int x, int y) {
        return fac[x] * inv[y] % P * inv[x - y] % P;
    }
    
    int main() {
        read(n), read(m), read(K);
        
        for(int i = fac[0] = 1; i <= n + m; i++) 
            fac[i] = 1LL * fac[i - 1] * i % P;
        inv[n + m] = pow(fac[n + m], P - 2);
        for(int i = n + m - 1; i >= 0; i--)
            inv[i] = 1LL * inv[i + 1] * (i + 1) % P;
        
    //    printf("%lld
    ", getC(7, 3));
        
        for(int i = 1; i <= K; i++) 
            read(a[i].x), read(a[i].y);
    //    a[++K].x = 1, a[K].y = 1;
        sort(a + 1, a + 1 + K, cmp);
          
        ll ans = getC(m + n - 2, m - 1);  
        for(int i = K; i >= 1; i--) {
            f[i] = (f[i] + getC(m + n - a[i].x - a[i].y, m - a[i].y) + P) % P;
            for(int j = i + 1; j <= K; j++) 
                if(a[j].x >= a[i].x && a[j].y >= a[i].y)
                    f[i] = (f[i] - f[j] * getC(a[j].x - a[i].x + a[j].y - a[i].y, a[j].y - a[i].y) % P + P) % P;
            ans = (ans - f[i] * getC(a[i].x + a[i].y - 2, a[i].y - 1) % P + P) % P;
        }
        
        printf("%lld
    ", ans);
        return 0;
    }
    View Code
  • 相关阅读:
    Python3+PyMysql
    Python3 pip
    Python日志模块封装
    SVN状态图标无法显示
    添加修改数据库表以及字段描述信息
    群晖 6 控制面板信息中心 空白解决
    nextcloud迁移后报权限问题
    ESXI中第三方sata卡遇到的问题“对 CDROM 映像文件 执行操作失败”
    网站推荐 印章制作大师
    转 黑群晖7.0.1和6.0 中Active Backup for Business套件激活方法
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9636723.html
Copyright © 2020-2023  润新知