zoukankan      html  css  js  c++  java
  • 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
    ",cas++);
                continue;
            }
            sort ( P , P+cnt+1 );
            if(cnt>=1&&P[cnt-1]==P[cnt]){
                printf("Case #%d: 0
    ",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
    " ,cas++, dp[cnt] );
        }
    }
    



  • 相关阅读:
    利用数组将九种颜色不重复的显示在九个盒子中
    gulp结合webpack开启多页面模式,配置如下
    parent获取子元素以及自身元素
    利用键值对来找对应值的信息
    Math.random 随机数方法
    常用linux,DOS命令——持续更新
    函数嵌套函数传递this值
    空对象模式
    状态模式(状态机)
    观察者模式
  • 原文地址:https://www.cnblogs.com/zhangxianlong/p/10672545.html
Copyright © 2011-2022 走看看