HDU5794 - A Simple Chess

HDU5794 - A Simple Chess


做法:首先的想法就是用总方案数减去,经过过障碍的方案数A。第一个思路就是容斥,但是显然不符合数据规模。另一个思路就是将障碍物从左上到右下排序,dp[i] 表示不经过前i-1个障碍,到达第i个障碍的方案数。这里定义cal(a,b) 表示从a到b,无障碍情况下的方案数,a[i]是排序后的第i个点,起点st,终点ed,pre(a)表示能到达a的点集。那么 \(A = \sum_{i=1}^n dp[i]*cal(a[i],ed)\),现在考虑转移,dp[i] 就是 到达pre(a[i])中每个点的不经过任何障碍的方案数的和,而这个值与答案类似可以通过用总方案减去,之前经过过障碍的方案数,这些dp值已经求出来了,直接转移即可。cal(a,b) 中需要注意组合数的计算过程。lucas实现的时候没有判n和m的正负,RE了很长一段时间。。

#include <cstdio>
#include <algorithm>
typedef long long ll;
const int mod = 110119;
using namespace std;
ll n, m, dp[111], tmp, ans;
int r;
ll f[mod], rv[mod];
ll C(ll n, ll m) {
    return n < m ? 0: f[n]*rv[n-m]%mod*rv[m]%mod;
}
ll lucas(ll n, ll m) {
    if(n<m || n < 0 || m < 0) return 0;
    ll ans=1;
    for(; m; n/=mod, m/=mod) ans = ans*C(n%mod, m%mod)%mod;
    return ans;
}
struct node {
    ll x, y;
    node(){}
    node(ll _x, ll _y) {
        x = _x; y = _y;
    }
}a[111];
bool cmp(node a,node b) {
    return (a.x + a.y) <= (b.x + b.y);
}
int inb(node a) {
    if(a.x < 1 || a.x > n || a.y < 1 || a.y > m) return 0;
    return 1;
}
node pre1(node a) {
    return node(a.x-2LL,a.y-1LL);
}
node pre2(node a) {
    return node(a.x-1LL,a.y-2LL);
}
ll cal(node a, node b) {
    if( !inb(a) || !inb(b) ) return 0;
    ll x = b.x - a.x + 1, y = b.y - a.y + 1;
    if(x == 1 && y == 1) return 1;
    if( !inb(node(x,y)) ) return 0;
    if(x + y - 2 < 0) return 0;
    if( (x+y-2)%3 ) return 0;

    ll k = (x+y-2)/3LL;
    ll num = x-k-1;

    return lucas(k, num);
}
int main() {
    rv[0] = rv[1] = f[0] = f[1] = 1;
    for(int i = 2; i < mod; ++i) {
        f[i] = f[i-1]*i % mod; rv[i] = -rv[mod%i]*(mod/i)%mod;
        while(rv[i] < 0) rv[i] += mod;
    }
    for(int i = 2; i < mod; ++i) rv[i] = rv[i]*rv[i-1]%mod;
    int C = 0;
    while(scanf("%lld %lld %d", &n, &m, &r) != EOF) {
        for(int i = 1; i <= r; ++i) scanf("%lld %lld", &a[i].x, &a[i].y);
        sort(a+1, a+1+r, cmp);
        ans = cal(node(1,1), node(n,m));
        for(int i = 1; i <= r; ++i) {
            dp[i] = tmp = 0;
            for(int j = 1; j < i; ++j) {
                tmp += dp[j]*cal(a[j],pre1(a[i]))%mod;
                tmp += dp[j]*cal(a[j],pre2(a[i]))%mod;
                tmp %= mod;
            }
            dp[i] = cal(node(1,1), pre1(a[i]))%mod + cal(node(1,1), pre2(a[i]))%mod - tmp;
            ((dp[i]%=mod) += mod)%=mod;
            ans -= dp[i]*cal(a[i],node(n,m))%mod;
            ((ans%=mod) += mod)%=mod;
        }
        printf("Case #%d: %lld\n",++C,ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/RRRR-wys/p/9853829.html