zoukankan      html  css  js  c++  java
  • 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;
    }
    more crazy more get!
  • 相关阅读:
    机器学习--避免过度拟合 笔记
    《机器学习》第三章 决策树学习 笔记加总结
    《机器学习》第二章 概念学习和一般到特殊序
    《机器学习》第一章 引言 笔记加总结
    jmeter+ant生成html报告
    jmeter之beanshell使用
    html常用标签
    css样式
    fiddler设置重定向
    fiddler设置断点
  • 原文地址:https://www.cnblogs.com/wethura/p/9918166.html
Copyright © 2011-2022 走看看