zoukankan      html  css  js  c++  java
  • codeforces(559C)--C. Gerald and Giant Chess(组合数学)

    C. Gerald and Giant Chess
    time limit per test
    2 seconds
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    Giant chess is quite common in Geraldion. We will not delve into the rules of the game, we'll just say that the game takes place on anh × w field, and it is painted in two colors, but not like in chess. Almost all cells of the field are white and only some of them are black. Currently Gerald is finishing a game of giant chess against his friend Pollard. Gerald has almost won, and the only thing he needs to win is to bring the pawn from the upper left corner of the board, where it is now standing, to the lower right corner. Gerald is so confident of victory that he became interested, in how many ways can he win?

    The pawn, which Gerald has got left can go in two ways: one cell down or one cell to the right. In addition, it can not go to the black cells, otherwise the Gerald still loses. There are no other pawns or pieces left on the field, so that, according to the rules of giant chess Gerald moves his pawn until the game is over, and Pollard is just watching this process.

    Input

    The first line of the input contains three integers: h, w, n — the sides of the board and the number of black cells (1 ≤ h, w ≤ 105, 1 ≤ n ≤ 2000).

    Next n lines contain the description of black cells. The i-th of these lines contains numbers ri, ci (1 ≤ ri ≤ h, 1 ≤ ci ≤ w) — the number of the row and column of the i-th cell.

    It is guaranteed that the upper left and lower right cell are white and all cells in the description are distinct.

    Output

    Print a single line — the remainder of the number of ways to move Gerald's pawn from the upper left to the lower right corner modulo109 + 7.

    Sample test(s)
    input
    3 4 2
    2 2
    2 3
    
    output
    2
    
    input
    100 100 3
    15 16
    16 15
    99 88
    
    output
    545732279
    


    题目大意:给出一个棋盘为h*w,如今要从(1,1)到(h,w)。当中有n个黑点不能走,问有多少种可能从左上到右下(1,1和h,w永远是能够走的)

    计算左上到右下的方法假设不考虑黑点的话,sum=C(h+w)(h)

    由于存在黑点i(x,y),所以用所以计算从左上到黑点的方法有sum[i] = C(x+y)(x)。当中假设在黑点的左上还有黑点j(u,v),那么应该减去sum[j]*C(x-u+y-v)(y-u)。去掉全部在左上的黑点的影响就能够得到由左上到第i点的真正的方法数

    从左上的第一个黑点。一直计算到右下(h,w)

    注意:

    1、C(h+w)(h)的数据非常大。C(h+w)(h) = (h+w)!/( h!*w! )。用数组fac记录下每一个数的阶乘

    2、计算组合数的时候有除法,能够用逆元来做a/b%mod = a*(b^(mod-2))%mod。计算i的阶乘的逆元inv[i],第在对阶乘求逆元的方法还有inv[ fac[i] ] = inv[ fac[i+1] ]*(i+1)%mod ,这种方法仅对连续的阶乘有效。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std ;
    #define LL __int64
    const LL MOD = 1e9+7 ;
    struct node{
        LL x , y ;
    }p[3100];
    LL h , w , n ;
    LL fac[310000] , inv[310000] ;
    LL sum[3100] ;
    int cmp(node a,node b) {
        return a.x < b.x || (a.x == b.x && a.y < b.y) ;
    }
    LL pow(LL x,LL k) {
        LL ans = 1 ;
        while( k ) {
            if( k&1 ) ans = ans*x%MOD ;
            k = k>>1 ;
            x = (x*x)%MOD ;
        }
        return ans ;
    }
    void init() {
        LL i , j , c ;
        fac[0] = inv[0] = 1 ;
        for(i = 1 ; i <= h+w ; i++)
            fac[i] = (fac[i-1]*i)%MOD ;
        c = max(h,w) ;
        inv[c] = pow(fac[c],MOD-2) ;
        for(i = c-1 ; i > 0 ; i--) {
            inv[i] = inv[i+1]*(i+1)%MOD ;
        }
    }
    int main() {
        LL i , j ;
        LL ans ;
        while( scanf("%I64d %I64d %I64d", &h, &w, &n) != EOF ) {
            init() ;
            for(i = 0 ; i < n ; i++)
                scanf("%I64d %I64d", &p[i].x, &p[i].y) ;
            p[n].x = h ; p[n++].y = w ;
            sort(p,p+n,cmp) ;
            int x1 , y1 , x2 , y2 ;
            for(i = 0 ; i < n ; i++) {
                x1 = p[i].x-1 ; y1 = p[i].y-1 ;
                sum[i] = fac[x1+y1]*inv[x1]%MOD*inv[y1]%MOD ;
                for(j = 0 ; j < i ; j++) {
                    if( p[j].x <= p[i].x && p[j].y <= p[i].y ) {
                        x2 = x1 - p[j].x+1 ; y2 = y1 - p[j].y+1 ;
                        sum[i] = (sum[i]-fac[x2+y2]*inv[x2]%MOD*inv[y2]%MOD*sum[j]%MOD)%MOD ;
                        if( sum[i] <= 0 ) sum[i] = (sum[i]+MOD)%MOD;
                    }
                }
            }
            printf("%I64d
    ", sum[n-1]) ;
        }
        return 0 ;
    }
    


  • 相关阅读:
    WOJ 1055
    做人做事
    实现Runnable接口和扩展Thread使用场景
    利用Perf4j 对java项目进行性能监控
    android画笔错位问题的解决
    IE常见的CSS的BUG(二)
    激动啊,终于诞生了,编译了属于俺自己的 JDK
    图像处理特征不变算子系列之Moravec算子(一)
    对象的动态建立和释放
    用TinyXml2读取XML文件的一个简单Demo
  • 原文地址:https://www.cnblogs.com/tlnshuju/p/7235290.html
Copyright © 2011-2022 走看看