A Simple Chess (Lucas组合数 + 容斥)

Posted wethura

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了A Simple Chess (Lucas组合数 + 容斥)相关的知识,希望对你有一定的参考价值。

  题意:走马步,要求向右向下,不能走进禁止的点。求方案数。

  思路:若是n*m比较小的话,那么可以直接DP。但是这道题目不行。不过我们仔细分析可以知道从某个点到某个点是一个组合数,但是数据太大,mod值很小,所以只能用Lucas定理。然后DP一下到某个点不经过之前的点的方案数一直推下去就可以得到最终答案了。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int maxn = 1e3 + 7;
const int maxm = 2e5 + 7;
const int mod  = 110119;

ll fac[maxm], refac[maxm], dp[maxm];

ll mypow(ll a, ll p, ll mo){
    ll ret = 1;
    while(p){
        if(p & 1) ret = ret * a % mo;
        a = a * a % mo;
        p >>= 1;
    }
    return ret;
}

void init(){
    refac[0] = refac[1] = fac[0] = fac[1] = 1LL;
    for(int i = 2; i < mod; i ++) fac[i] = 1LL * fac[i - 1] * i % mod;
    refac[mod - 1] = mypow(fac[mod - 1], mod - 2, mod);
    for(int i = mod - 2; i > 0; i --) refac[i] = 1LL * refac[i + 1] * (i + 1) % mod;
}

ll comb(int a, int b){
    if(a < b) return 0;
    return fac[a] * refac[b] % mod * refac[a - b] % mod;
}

ll lucas(ll n, ll m){
    if(!m) return 1;
    return comb(n % mod, m % mod) * lucas(n/mod, m/mod) % mod;
}

struct P{
    ll x, y;
    P(){}
    P(ll a, ll b):x(a), y(b){}
    bool operator < (const P & t) const{
        return x + y < t.x + t.y;
    }
    bool check(const P & t){
        if(x <= t.x || y <= t.y) return false;
        ll a = x - t.x, b = y - t.y ;
        if((a + b) % 3 != 0 || a > 2* b || 2 * a < b) return false;
        return true;
    }
    ll cnt(const P & t){
        ll dx = x - t.x, dy = y - t.y;
        ll step = (dx + dy) / 3;
        return lucas(step, dx - step);
    }
};
P in[maxn];



int main(){
    init();
    int ncase = 1;
    ll n, m;
    int k;

    while(~scanf("%lld%lld%d", &n, &m, &k)){
        memset(dp, 0, sizeof(dp));
        bool flag = true;
        for(int i = 0; i < k; i ++) {
            scanf("%lld%lld", &in[i].x, &in[i].y);
            if(in[i].x == n && in[i].y == m) flag = false;
        }
        if(!flag) {
            printf("Case #%d: 0
", ncase ++);
            continue;
        }
        if(n == 1 && m == 1) {
            printf("Case #%d: %lld
", ncase ++, 1LL);
            continue;
        }
        sort(in, in + k);
        in[k].x = n, in[k].y = m;
        for(int i = 0; i <= k; i ++){
            if(!in[i].check(P(1, 1))) continue;
            dp[i] = in[i].cnt(P(1, 1));
            for(int j = 0; j < i; j ++){
                if(!dp[j] || !in[i].check(in[j])) continue;
                dp[i] = ((dp[i] - dp[j] * in[i].cnt(in[j])) % mod + mod ) % mod;
            }
        }
        printf("Case #%d: %lld
", ncase ++, dp[k]);
    }
    return 0;
}

 

以上是关于A Simple Chess (Lucas组合数 + 容斥)的主要内容,如果未能解决你的问题,请参考以下文章

hdu-5794 A Simple Chess(容斥+lucas+dp)

HDU 6114 Chess逆元+组合数(组合数模板题)

组合数取模(Lucas)

求大的组合数模板 利用Lucas定理

组合数模板 - Lucas

hdu 3037 费马小定理+逆元求组合数+Lucas定理