1. 程式人生 > >A Simple Chess (Lucas組合數 + 容斥)

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\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; }