HDU 5794 容斥原理+Lucas

http://acm.hdu.edu.cn/showproblem.php?pid=5794

 

题意: 马在(1,1)走到(n,m)有些地方设置了障碍物不能走。。问方案总数是多少?

 

思路:题外话考虑如果不是马是兵。。其实就是一道CF的原题。。。

是马的话其实和兵的思路是一样的,唯一稍微有困难的是要求出(1,1)到(x,y)的方案数    结论是   Lucas ( (x+y)/3 , ((x+y)/3-abs(x-y))/2 )

因为是大组合数取模,显然想到卢卡斯定理,这里就不做详细说明。。。

接下来就是容斥部分。。。首先r有100.。。。肯定不是2^100这样容斥。。太蠢了。。。这个使用的是类似dp的方法,把每个障碍物的最终方案数求出来。。那两个和三个举栗子。。两个肯定是第二个的方案数减去第一个的方案数乘以第一个到第二个的方案数 。。那接下来看第三个。。其实就是第三个的方案数减去第一个的方案数乘以第一个到第三个的方案数并且减去 第二个的方案数乘以第二个到第三个的方案数  。。仔细推敲一下用集合的方法表示一下,我们会发现这恰好就是一个容斥的过程。。归纳一下我们就知道了到第N个的方法了。。。

 

最后!需要注意的是要判断终点有没有障碍物。。障碍物之间是否可以到达!!!(当时WA到死。。)

 

代码:

 

 

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define MAX 105

using namespace std;

typedef long long LL;

const LL mod = 110119;
const LL p= 110119;

LL dp[MAX];
long long h,w,n;
struct Node{
    long long x,y;
    bool operator < ( const Node & a ) const{
        return x+y < a.x+a.y;
    }
    bool operator == ( const Node & a ) const{
        return x==a.x&&y==a.y;
    }
}P[MAX];

long long  fac[p+10];

void init(){
    int i;
    fac[0] =1;
    for(i =1; i <= p; i++)
        fac[i] = fac[i-1]*i % p;
}

long long pow(long long a, long long b){
    long long tmp = a % p, ans =1;
    while(b){
        if(b &1)  ans = ans * tmp % p;
        tmp = tmp*tmp % p;
        b >>=1;
    }
    return  ans;
}

long long C(long long n, long long m){
    if(m > n)  return 0;
    return  fac[n]*pow(fac[m]*fac[n-m], p-2) % p;
}

long long Lucas(long long n, long long m){
    if(m<0) return 0;
    if(m ==0)  return 1;
    else return  (C(n%p, m%p)*Lucas(n/p, m/p))%p;
}

bool ok(Node T){
    if((T.x+T.y)%3==2&&abs(T.x-T.y)<=(T.x+T.y)/3&&T.x<=h&&T.y<=w) return true;
    else return false;
}

int main (){
    init ();

    int cas=1;
    while ( scanf ("%lld%lld%lld" , &h , &w , &n )!=EOF ){
        int cnt=0;
        for ( int i = 0 ; i < n ; i++ ){
            scanf ("%lld%lld" , &P[i].x , &P[i].y );
            if(ok(P[i])){
                P[cnt].x=P[i].x;
                P[cnt].y=P[i].y;
                cnt++;
            }
        }
        P[cnt].x = h , P[cnt].y = w;
        if(!ok(P[cnt])){
            printf("Case #%d: 0\n",cas++);
            continue;
        }
        sort ( P , P+cnt+1 );
        if(cnt>=1&&P[cnt-1]==P[cnt]){
            printf("Case #%d: 0\n",cas++);
            continue;
        }
        memset ( dp , 0 , sizeof ( dp ));
        for ( int i = 0; i <= cnt ; i++ ){
            long long x = P[i].x , y = P[i].y;
            dp[i] = Lucas ( (x+y)/3 , ((x+y)/3-abs(x-y))/2 );
            for ( int j = 0 ; j < i ; j++ ){
                long long u = P[j].x , v = P[j].y;
                if ( u > x || v > y ) continue;
                dp[i] -= Lucas( (x-u+1+y-v+1)/3 , ((x-u+1+y-v+1)/3-abs(x-u-y+v))/2 )*dp[j]%mod;
                dp[i] = (dp[i]%mod+mod)%mod;
            }
        }
        printf ( "Case #%d: %lld\n" ,cas++, dp[cnt] );
    }
}



posted @ 2016-08-06 16:08  zhangxianlong  阅读(79)  评论(0编辑  收藏  举报