HDU_5794_ASimpleChess(Lucas定理&&(容斥||dp))

A Simple Chess

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


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 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
2016 Multi-University Training Contest 6
 

Recommend
wange2014


题意

有个很大的棋盘,然后棋子可以走马步(横走1竖走2或横走2竖走1)

然后给一个子从1,1走到n,m

只能往格子坐标增大的方向跳

棋盘中有一些障碍物

问方案数。


解题思路

如果棋子走1,1应该是都见过的情况

组合数学直接求C(n+m,n)即可

其实变成1,2也没区别,只是此时存在了不能走的情况

想想每次走一步对于两个方向的总贡献是3

因此至少两个格点的坐标差值dx,dy的和是3的倍数才行

而步数就是st=(dx+dy)/3

那么每个方向上走2格的次数就分别是

nx=x-st,和ny=y-st

因为不能走回头路,因此这两个数值要大于零


然后就又变成了组合数学问题

nx+ny步中选nx步横向走2

于是方案数就是C(nx+ny,nx)

由于数字很大,模的数比较小,这里用Lucas定理处理大组合数取模的问题


接下来考虑解决路径上的障碍物了

可行方案数=总方案数-路过了至少一个障碍的方案数

由于障碍物的数量有100之多

裸容斥显然是会爆炸的

但是由于棋子走是有方向性的

如从左下到右上可走

则只有更左下的点到更右上的点才有重复

则可以按照左下到右上的方向排序。

这里考虑dp的方法

dp[I]表示起始点到i障碍不过任何障碍的路径数

因此dp[i]只要算出起点到i点的所有路径数,再减掉前i-1个点自己的路径数*(i-1中某个点到I点路径数)

即可。

接下来路过至少一个障碍的方案数=

sigma(dp[i]*i点到n,m点的路径数)

为什么呢?想想dp[1]*1到终点路径数,算出了哪些?

过1点的所有路径。

dp[2]*2到终点路径数呢?不过1点过2点的所有路径数

dp[3]*3到终点路径数呢?不过1点不过2点过3点的所有路径数


因此整个计数过程完备且没有重复,即为所求。

至此问题得解


#include 
#include 
#include 
#include 
using namespace std;

typedef long long LL;

const int M=105;
const int MO=110119;

//以下lucas定理
LL qp(LL a,LL n,LL mo)
{
    LL ans=1;
    while(n)
    {
        if(n&1)
            ans=(ans*a)%mo;
        a=(a*a)%mo;
        n>>=1;
    }
    return ans;
}
struct Lucas
{
    LL p;
    LL fa[MO],inv[MO];//阶乘和逆元,注意空间大小
    void init(LL _p)
    {
        p=_p;
        fa[0]=1;
        for(int i=1;in)
            return 0;
        return fa[n]*inv[fa[n-m]*fa[m]%p]%p;
    }
    LL lucas(LL n,LL m)//大组合数取模
    {
        if(n==m||m==0)
            return 1;
        if(m>n)
            return 0;
        return c(n%p,m%p)*lucas(n/p,m/p)%p;
    }
}lu;

struct Ob //障碍物
{
    LL x,y;
    bool operator<(const Ob &a)const
    {
        return x+y

你可能感兴趣的:(HDU_5794_ASimpleChess(Lucas定理&&(容斥||dp)))