码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-11-06 22:30:05      阅读:188      评论:0      收藏:0      [点我收藏+]

标签:set   scanf   operator   ==   mod   div   mem   long   mes   

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

  思路:若是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\n", ncase ++);
            continue;
        }
        if(n == 1 && m == 1) {
            printf("Case #%d: %lld\n", 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\n", ncase ++, dp[k]);
    }
    return 0;
}

 

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

标签:set   scanf   operator   ==   mod   div   mem   long   mes   

原文地址:https://www.cnblogs.com/wethura/p/9918166.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!