【dp每日一题】CF 559C. Gerald and Giant Chess

大意:

从左上角移动到右下角,其中有k个黑块不能走,问方案数

思路:

从左上角到有下角,方案为(C_{n+m}^{n}),先将黑点从左上到右下排个序,(dp[i])代表走到当前黑点的方案数,它可以根据左上方的(dp[i])转移过来,(dp[i]=C_{x_i+y_i}^{x_i}-sum{dp[j]*C_{x_j+y_j}^{x_j}}),最后把右下角作为一个黑块一起求得即可

#include<bits/stdc++.h>

using namespace std;
typedef long long LL;
const LL N = 1e6 + 5,mod = 1e9+7;

LL n, m,k,dp[N];
LL fact[N], infact[N];

LL qmi(LL a, LL k, LL p) {
    LL res = 1;
    while (k) {
        if (k & 1) res = res * a % p;
        k >>= 1;
        a = a * a % p;
    }
    return res;
}

// 预处理
void init() {
    fact[0] = infact[0] = 1;
    for (int i = 1; i < N; ++i) {
        fact[i] = (LL)fact[i - 1] * i % mod;
        infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
    }
}

LL c(int a,int b){
    return (LL)fact[a] * infact[b] % mod * infact[a - b] % mod;
}

struct node{
    int x, y;
} h[3000];

bool cmp(node a,node b){
    return a.x < b.x || (a.x == b.x && a.y < b.y);
}

int main(){
    init();
    cin >> n >> m >> k;
    for (int i = 0; i < k;i++){
        dp[i] = 0;
        cin >> h[i].x >> h[i].y;
    }
    h[k].x = n, h[k].y = m;
    dp[k] = 0;
    sort(h,h+k+1,cmp);
    for (int i = 0; i <= k;i++){
        dp[i] = c(h[i].x + h[i].y - 2, h[i].x - 1);
        for (int j = 0; j < i;j++){
            if(h[i].x>=h[j].x&&h[i].y>=h[j].y)
                dp[i] = (dp[i] - dp[j] * c(h[i].x + h[i].y - h[j].y - h[j].x, h[i].x - h[j].x) % mod + mod)  % mod;
        }
    }
    cout << dp[k] << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/dyhaohaoxuexi/p/14067048.html