• 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!
  • 相关阅读:
    【BZOJ3166】ALO(主席树)
    【UOJ#188】Sanrd(min_25筛)
    伯努利数
    【51Nod1258】序列求和V4(FFT)
    【BZOJ5306】[HAOI2018]染色(NTT)
    【BZOJ4943】【NOI2017】蚯蚓排队(哈希)
    【BZOJ4912】天才黑客(最短路,虚树)
    【BZOJ5333】荣誉称号(动态规划)
    NOI2018前的每日记录
    【BZOJ1088】扫雷(递推)
  • 原文地址:https://www.cnblogs.com/wethura/p/9918166.html
Copyright © 2020-2023  润新知