• 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
  • 相关阅读:
    Java基础(十四)——API(Calendar类、System类、StringBuilder类、包装类)
    异常
    Java基础(十三)——权限修饰符和内部类
    知识点总结
    Java基础(十二)— —多态
    Java基础(十一)— —继承、抽象类和接口
    java基础(十)——继承
    小程序外部向组件内部传递externalClasses -- 传入样式wxss
    小程序组件交互 -- 传入js
    promise封装小程序的请求类(request,清爽易懂)
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9636723.html
Copyright © 2020-2023  润新知