HDU 5794 A Simple Chess(卢卡斯定理 + 容斥原理)

227 篇文章 0 订阅
39 篇文章 0 订阅

传送门

A Simple Chess

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 667    Accepted Submission(s): 168


Problem Description
There is a n×m board, a chess want to go to the position
(n,m) from the position (1,1) .
The chess is able to go to position (x2,y2) from the position (x1,y1) , only and if only x1,y1,x2,y2 is satisfied that
(x2x1)2+(y2y1)2=5, x2>x1, y2>y1 .<br>Unfortunately, there are some obstacles on the board. And the chess never can stay on the grid where has a obstacle.<br>I want you to tell me, There are how may ways the chess can achieve its goal. </div><div class=panel_bottom>&nbsp;</div><br><div class=panel_title align=left>Input</div> <div class=panel_content>The input consists of multiple test cases.<br>For each test case:<br>The first line is three integers, n,m,r,(1n,m1018,0r100) , denoting the height of the board, the weight of the board, and the number of the obstacles on the board.<br>Then follow r lines, each lines have two integers, x,y(1xn,1ym), denoting the position of the obstacles. please note there aren't never a obstacles at position (1,1) .</div><div class=panel_bottom>&nbsp;</div><br><div class=panel_title align=left>Output</div> <div class=panel_content>For each test case,output a single line &quot;Case #x: y&quot;, where x is the case number, starting from 1. And y is the answer after module 110119 .
 

Sample Input
  
  
1 1 0
3 3 0
4 4 1
2 1
4 4 1
3 2
7 10 2
1 2
7 1
 

Sample Output
  
  
Case #1: 1
Case #2: 0
Case #3: 2
Case #4: 1
Case #5: 5
 

Author
UESTC
 

Source

题目大意:
给一个 nm 的方格,让你以象棋中”马”的方式从 (11) 点走到 (n,m) 点的方法数对 MOD 取模,(“马”的方式只能向右上方),中间会有一些障碍。

解题思路:
卢卡斯定理加上容斥, (1,1) 点到 (n,m) 点,如果中间有 (x,y) 点的障碍的话,那么一定是 (1,1) 点到 (n,m) 点的方法数 c (1,1) 点到 (x,y) 点的方法数 b (x,y) 点到 (n,m) 点的方法数 c 。也就是 ans=cab,中间会遇到很大的组合数取模的问题,也就是会用到卢卡斯定理(辅助手段)
My Code

#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <cmath>
using namespace std;

typedef long long LL;
const LL MOD = 110119LL;
struct Node
{
    LL x, y, s;
} node[105];

int cmp(const Node s1,const Node s2)
{
    if(s1.x==s2.x)
        return s1.y<s2.y;
    return s1.x<s2.x;
}

LL PowMOD(LL a,LL b,LL MOD)
{
    LL ret=1;
    while(b)
    {
        if(b&1) ret=(ret*a)%MOD;
        a=(a*a)%MOD;
        b>>=1;
    }
    return ret;
}

LL fac[1000005];

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

LL Lucas(LL n,LL m,LL p)
{
    LL ret=1;
    while(n&&m)
    {
        LL a=n%p,b=m%p;
        if(a<b) return 0;
        ret=(ret*fac[a]*PowMOD(fac[b]*fac[a-b]%p,p-2,p))%p;
        n/=p;
        m/=p;
    }
    return ret;
}

int main()
{
    LL n,m;
    int r;
    int Case=1;
    Get_Fact(MOD);
    while(scanf("%lld%lld%d",&n,&m,&r)!=EOF)
    {
        int tot=0;
        LL sum=0;
        int flag=0;
        if((n+m+1)%3==0)
        {
            LL s=(n+m+1)/3;
            if(n>=s&&m>=s)
            {
                LL t=n;
                n=2*s-m;
                m=2*s-t;
            }
            else
            {
                flag=1;
            }
        }
        else
        {
            flag=1;
        }
        for(int i=0; i<r; i++)
        {
            LL x,y;
            scanf("%lld%lld",&x,&y);
            if((x+y+1)%3==0)
            {
                LL s=(x+y+1)/3;
                if(x>=s&&y>=s)
                {
                    node[tot].x=2*s-y;
                    node[tot].y=2*s-x;
                    if(node[tot].x<=n&&node[tot].y<=m)
                        tot++;
                }
            }
        }
        if(flag==1)
        {
            printf("Case #%d: %lld\n",Case++,sum);
            continue;
        }
        if(tot>0)
            sort(node,node+tot,cmp);
        sum=Lucas(n+m-2,n-1,MOD)%MOD;
        for(int i=0; i<tot; i++)
        {
            node[i].s=Lucas(node[i].x+node[i].y-2,node[i].x-1,MOD)%MOD;
        }
        for(int i=0; i<tot; i++)
        {
            LL tt=Lucas(n-node[i].x+m-node[i].y,m-node[i].y,MOD);
            for(int j=i+1; j<tot; j++)
            {
                if(node[j].y>=node[i].y)
                {
                    LL d1=node[j].y-node[i].y;
                    LL d2=node[j].x-node[i].x;
                    node[j].s=(node[j].s-(node[i].s*Lucas(d1+d2,d1,MOD))%MOD)%MOD;
                }
            }
            sum=(sum-(node[i].s*tt)%MOD)%MOD;
            sum = (sum%MOD+MOD)%MOD;
        }
        printf("Case #%d: %lld\n",Case++,sum);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值