hdu 5794 A Simple Chess(Lucas 定理)

来源:互联网 发布:剑灵捏脸数据龙男 编辑:程序博客网 时间:2024/06/05 19:01

A Simple Chess

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


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.
Unfortunately, there are some obstacles on the board. And the chess never can stay on the grid where has a obstacle.
I want you to tell me, There are how may ways the chess can achieve its goal.
 

Input
The input consists of multiple test cases.
For each test case:
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.
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).
 

Output
For each test case,output a single line "Case #x: y", where x is the case number, starting from 1. And y is the answer after module110119.
 

Sample Input
1 1 03 3 04 4 12 14 4 13 27 10 21 27 1
 

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

题意: 题目意思抽象出来就是一个n*m的矩阵,你从左上走到右下有多少种方式,只能走日字型,走的格子必须是右下方,而且规定一些方格是不能走的。


思路:如果不考虑不能走的方格,稍微自己化个图就能很清楚的发现规律;

定义最左上点为(0,0);

可知,只有格点横纵坐标和为3的倍数的某些点才能够到达。

相同横纵坐标和的格点的方案数是按照排列数的值分布的。



这个规律找出来之后就相对好做了。

有些点是不能走的。

那就计算这些点对到达末点的贡献度,减去就好了。


代码:

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;typedef long long ll;const int mod=110119;struct node{    ll x,y,w;    bool operator<(const node&p)const    {        if(x!=p.x)            return x<p.x;        return y<p.y;    }}A[111];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[110219];ll 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,t=0;    Get_Fact(mod);    while(scanf("%I64d%I64d%d",&n,&m,&r)!=EOF)    {        n--,m--;        int len=0;        for(int i=0;i<r;i++)        {            ll a,b;            scanf("%I64d%I64d",&a,&b);            a--;            b--;            if((a+b)%3)                continue;            ll cc=a+b;            cc/=3;            if(b<cc||b>cc*2+1)                continue;            A[len].x=a;A[len].y=b;A[len].w=0;            len++;        }        sort(A,A+len);        ll cc=n+m;        if(cc%3||m<cc/3||m>cc/3*2+1)        {            printf("Case #%d: 0\n",++t);            continue;        }        cc/=3;        ll ans=Lucas(cc,m-cc,mod);        for(int i=0;i<len;i++)        {            ll x=A[i].x,y=A[i].y;             cc=x+y;            if(cc%3||y<cc/3||y>cc/3*2+1)                continue;            cc/=3;            ll res=Lucas(cc,y-cc,mod);            A[i].w=res;        }        for(int i=0;i<len;i++)        {            for(int j=i+1;j<len;j++)            {                ll x=A[j].x-A[i].x,y=A[j].y-A[i].y;                cc=x+y;                if(cc%3||y<cc/3||y>cc/3*2+1)                    continue;                cc/=3;                ll res=Lucas(cc,y-cc,mod);                A[j].w-=A[i].w*res%mod;                A[j].w=(A[j].w%mod+mod)%mod;            }            ll x=n-A[i].x,y=m-A[i].y;            cc=x+y;            if(cc%3||y<cc/3||y>cc/3*2+1)                continue;            cc/=3;            ll res=Lucas(cc,y-cc,mod);            ans-=res*A[i].w%mod;            ans=(ans%mod+mod)%mod;        }        printf("Case #%d: %I64d\n",++t,ans);    }    return 0;}


2 0
原创粉丝点击