A Simple Chess---hdu5794(容斥+Lucas)

题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5794

题意:给你一个n*m的网格,问从(1, 1)走到(n, m)的方案数是多少,其中有r个点是不可到达的;

根据公式我们可以知道每次只能走”日"型;

路径如上图所示,我们可以看到有很多点是不可达的,可达点都是满足(x+y)%3=2的;路径可以看成一个斜着放置的杨辉三角。我们只需要把坐标转换一下即可,这是没有障碍时的方案数;

让(1,1)到(n,m)中如果有一个障碍,那么我们可以用起点到终点的方法数-起点到障碍点的方法数*障碍点到终点的方法数;同样如果有 r 个,那就减去r次这样的情况;

同样处理到达每个点的时候也是这样处理的;

注意有不可达的,所以判断一下不然会re的;

#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<math.h>
using namespace std;
#define N 120000
#define PI 4*atan(1.0)
#define mod 110119
#define met(a, b) memset(a, b, sizeof(a))
typedef long long LL;

struct node
{
    LL x, y;
    friend bool operator < (node p, node q)
    {
        if(p.x!=q.x)
            return p.x < q.x;
        return p.y < q.y;
    }
}a[105];

LL f[N] = {1};

LL Pow(LL a, LL b)
{
    LL ans = 1;
    while(b)
    {
        if(b&1)
            ans = ans*a%mod;
        b/=2;
        a = a*a%mod;
    }
    return ans%mod;
}

LL C(LL n, LL m)
{
    if(m>n)return 0;
    if(m == 0)return 1;
    LL ans = f[n] * Pow(f[m], mod-2)%mod * Pow(f[n-m], mod-2) % mod;
    return ans;
}
LL Lucas(LL n, LL m)
{
    if(n<0 || m<0)return 0;///会出现不可达的情况,所以注意判断,否则会re;
    if(m > n) return 0;
    if(m == 0) return 1;
    return C(n%mod, m%mod) * Lucas(n/mod, m/mod) % mod;
}

LL solve(LL x1, LL y1, LL x2, LL y2)
{
    if((x1+y1)%3 != 2)return 0;
    if((x2+y2)%3 != 2)return 0;

    LL ax = (x1+y1-2)/3;
    LL ay = y1 - 1 - ax;

    LL bx = (x2+y2-2)/3;
    LL by = y2 - 1 - bx;

    return Lucas(bx-ax, by-ay);
}


int main()
{
    for(int i=1; i<=110119; i++)
        f[i] = f[i-1]*i % mod;

    LL n, m;
    int t = 1, r;
    while(scanf("%I64d %I64d %d", &n, &m, &r)!=EOF)
    {
        LL ans[N];///起点到i的方案数;

        for(int i=1; i<=r; i++)
            scanf("%I64d %I64d", &a[i].x, &a[i].y);

        sort(a+1, a+r+1);///按x的升序排列,再按y的升序排列;

        LL sum = solve(1, 1, n, m);

        for(int i=1; i<=r; i++)
        {
            ans[i] = solve(1, 1, a[i].x, a[i].y);
            for(int j=1; j<i; j++)
            {
                ans[i] = ((ans[i] - ans[j]*solve(a[j].x, a[j].y, a[i].x, a[i].y)%mod) + mod) % mod;
            }
        }
        for(int i=1; i<=r; i++)
        {
            sum = (sum - ans[i]*solve(a[i].x, a[i].y, n, m)%mod + mod) % mod;
        }
        printf("Case #%d: %I64d\n", t++, sum);
    }
    return 0;
}
View Code

 

posted @ 2016-08-18 22:19  西瓜不懂柠檬的酸  Views(296)  Comments(0Edit  收藏  举报
levels of contents