A Simple Chess

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5794

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 (x2−x1)2+(y2−y1)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,(1≤n,m≤1018,0≤r≤100), 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(1≤x≤n,1≤y≤m), 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

Source


2016 Multi-University Training Contest 6


##题意:

在n*m的棋盘上,从左上角(1,1)走到右下角(n,m)有多少条路线.
每次只能向右下方走"L"型路线. (x,y) => (x+1,y+2) or (x+2, y+1);
棋盘上有n个(n

##题解:

问题一:如何计算路线数
如果不存在任何障碍,从点(x1,y1)到点(x2,y2):
①. 不能到达:由于走的是"L"型路线(类似象棋的马),所以有可能到不了.
每走一步实际上是移动了三个单位(包括上下方向),而起点到终点共有(x2-x1) + (y2-y1)个单位.
所以能走到的充分必要条件是:((x2-x1)+(y2-y1)) % 3 == 0 ; 且终点在起点的左下方(x2>x1 && y2>y1).
②. 如果能到达:走的步数是 step = (x2+y2-x1-y1) / 3.
走法有 "L"型{(x,y)=>(x+2,y+1)} 和 "倒L"型{(x,y)=>(x+1,y+2)} 两种.
无论怎么走都至少会在上下两方向上都减1. 所以上下两方向各剩下 s1=x2-x1-step 和 s2=y2-y1-step 个单位.
再用"L"型和"倒L"型去分配这剩下的单位. 即 C(s1+s2, s1) 或 C(s1+s2, s2).
(另解:先看成往右下走一格,再抉择往右还是往下.)
③. 由于坐标范围较大,而取模的p=110119较小且为质数.
所以这里用lucas公式来求组合数.
(一般的:数较小且mod较大时用逆元求组合数,数较大且mod较小时用lucas求组合数)
(由于上述公式中s1 s2有可能为负数,所以lucas里面一定要对负数组合数作特判) (论完美模版的重要性).

问题二:如何考虑障碍物
容斥 + DP:坐标范围较大,只能对障碍位置进行dp:
dp[i]: 从(1,1)到障碍i且不经过其他障碍的路线数.
转移方程:
dp[i] = (起点到障碍i的路线) - Σ(dp[j] * (障碍j到障碍i的路线))
(其中j为位于障碍i左上方的障碍,即j可以通过合法路径到达i. 因此处理时先对障碍坐标排序).

类似题目对比总结:
至今为止做过五个类似的题:
1. CF-560E [Gerald and Giant Chess](http://www.codeforces.com/problemset/problem/560/E)
每次只能往右或下走,方案数比较好求,逆元求组合数(坐标较小).
2. UVALive-6916 [Punching Robot](http://acm.hust.edu.cn/vjudge/contest/97671#problem/K)
每次只能往右或下走,方案数比较好求,Lucas求组合数(坐标较大).
3. Gym-100379J [Move the (p, q)-knight to the corner!](http://acm.hust.edu.cn/vjudge/contest/87224#problem/H)
这个题跟本题几乎一样,走"类L"型路线,Lucas求组合数.
4. NOIP1997-普及组 [街道](http://oj.tsinsen.com/A1110)
这个题是坐标较小(50*50),障碍是一个矩形区域,对非障碍位置DP+高精度即可.
5. HDU-5794 [本题](http://acm.hdu.edu.cn/showproblem.php?pid=5794)
走"L"型路线,Lucas求组合数.


##代码:
``` cpp
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define eps 1e-8
#define maxn 150
#define mod 110119
#define inf 0x3f3f3f3f
#define mid(a,b) ((a+b)>>1)
#define IN freopen("in.txt","r",stdin);
using namespace std;

LL F[mod+10];

void init(LL p)

{

F[0] = 1;

for(int i = 1;i <= p;i++)

F[i] = F[i-1]i%p;

}

LL inv(LL a,LL m)

{

if(a == 1)return 1;

return inv(m%a,m)
(m-m/a)%m;

}

/初始化init(p),调用Lucas(m,n,p)计算C_m_n%p/

LL Lucas(LL n,LL m,LL p)

{

if(n < 0 || m < 0 || m > n)

return 0;

LL ans = 1;

while(n&&m)

{

LL a = n%p;

LL b = m%p;

if(a < b)return 0;

ans = ansF[a]%pinv(F[b]*F[a-b]%p,p)%p;

n /= p;

m /= p;

}

return ans;

}

LL get_ans(LL n, LL m)

{

return Lucas(m+n, m, mod);

}

LL m,n;

int k;

LL path[150];

struct node{

LL x,y;

bool operator < (const node& b)const {

if(x == b.x) return y < b.y;

return x < b.x;

}

}block[150];

int main(int argc, char const *argv[])

{

//IN;

init(mod);

int ca = 1;
while(scanf("%I64d %I64d %d", &n, &m, &k) != EOF)
{
memset(path, 0, sizeof(path));
memset(block, 0, sizeof(block));
for(int i=1; i<=k; i++){
scanf("%I64d %I64d", &block[i].x, &block[i].y);
}
block[k+1].x = n; block[k+1].y = m;
sort(block+1, block+k+2); for(int i=1; i<=k+1; i++) {
/*先求(1,1)到block_i的路线条数*/
LL step = block[i].x + block[i].y - 2;
if(step % 3) continue;
path[i] = get_ans(block[i].x - 1 - step/3, block[i].y - 1 - step/3); /*依次减去经过了其它障碍的路线数*/
for(int j=1; j<i; j++) {
LL step = block[i].x + block[i].y - block[j].x - block[j].y;
if(block[j].y > block[i].y || block[j].x > block[i].x || step % 3) continue; LL tmp = get_ans(block[i].x - block[j].x - step/3, block[i].y - block[j].y - step/3); path[i] = (path[i] + mod - (path[j] * tmp) % mod) % mod;
}
} printf("Case #%d: %I64d\n", ca++, path[k+1]%mod);
} return 0;

}

HDU 5794 A Simple Chess (容斥+DP+Lucas)的更多相关文章

  1. HDU 5794 - A Simple Chess

    HDU 5794 - A Simple Chess题意: 马(象棋)初始位置在(1,1), 现在要走到(n,m), 问有几种走法 棋盘上有r个障碍物, 该位置不能走, 并规定只能走右下方 数据范围: ...

  2. HDU 5794 A Simple Chess dp+Lucas

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5794 A Simple Chess Time Limit: 2000/1000 MS (Java/O ...

  3. hdu-5794 A Simple Chess(容斥+lucas+dp)

    题目链接: A Simple Chess Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/Ot ...

  4. hdu5794 A Simple Chess 容斥+Lucas 从(1,1)开始出发,每一步从(x1,y1)到达(x2,y2)满足(x2−x1)^2+(y2−y1)^2=5, x2>x1,y2>y1; 其实就是走日字。而且是往(n,m)方向走的日字。还有r个障碍物,障碍物不可以到达。求(1,1)到(n,m)的路径条数。

    A Simple Chess Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)To ...

  5. HDU5794 A Simple Chess 容斥+lucas

    分析:转自http://blog.csdn.net/mengzhengnan/article/details/47031777 一点感想:其实这个题应该是可以想到的,但是赛场上并不会 dp[i]的定义 ...

  6. HDU 5794 A Simple Chess(杨辉三角+容斥原理+Lucas定理)

    题目链接 A Simple Chess 打表发现这其实是一个杨辉三角…… 然后发现很多格子上方案数都是0 对于那写可能可以到达的点(先不考虑障碍点),我们先叫做有效的点 对于那些障碍,如果不在有效点上 ...

  7. HDU 5794 A Simple Chess ——(Lucas + 容斥)

    网上找了很多人的博客,都看不太懂,还是大力学长的方法好. 要说明的一点是,因为是比较大的数字的组合数再加上mod比较小,因此用Lucas定理求组合数. 代码如下(有注释): #include < ...

  8. HDU 5794 A Simple Chess (Lucas + dp)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5794 多校这题转化一下模型跟cf560E基本一样,可以先做cf上的这个题. 题目让你求一个棋子开始在( ...

  9. HDU 5794 A Simple Chess Lucas定理+dp

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5794 题意概述: 给出一个N*M的网格.网格上有一些点是障碍,不能经过.行走的方式是向右下角跳马步.求 ...

随机推荐

  1. redis sentinel 配置

    在最小配置:master.slave各一个节点的情况下,不管是master还是slave down掉一个,“完整的”读/写功能都将受影响,这在生产环境中显然不能接受.幸好redis提供了sentine ...

  2. Linux kmalloc/kfree 源码解读

    kmalloc/kfree用于划分和回收内核空间低区内存的方法.改组方法没有直接通过伙伴系统进行内存的划分,通过slab算法进行分配的.同时也为每个CPU提供一个阵列缓存,用于提高分配效率.下面对改组 ...

  3. JSTL、EL、ONGL、Struts标签的区别与使用

     一.JSTL 来源 我们使用JSP开发信息展现非常方便,也可嵌入java代码用来实现相关逻辑,但同样带来了很多问题: jsp维护难度增加 出事提示不明确,不容易提示 分工不明确等 解决上面的问题可以 ...

  4. OEM status|start|stop

    OEM一旦建立以后,LINUX的主机名(hosts)就不要去改变. [oracle@redhat4 ~]$ emctl start dbconsoleOC4J Configuration issue. ...

  5. bzoj2878

    又是环套树dp,这次不是我擅长的类型 首先考虑树上的暴力,肯定是穷举起点然后以起点为根dp 我们用g[i]表示以点i为期望走的路径总长,答案就是1/n*Σ(g[i]/d[i]) (d[i]表示点度数) ...

  6. UVALive 4452 The Ministers' Major Mess(2-sat)

    2-sat.又学到了一种使用的方法:当确定选择某中状态A时,从它的对立状态A^1引一条边add(A^1,A),从而使凡是dfs经过对立状态,必然return false:即保证若存在一种可能性,必然是 ...

  7. RESTful API 设计最佳实践(转)

    背景 目前互联网上充斥着大量的关于RESTful API(为方便,下文中“RESTful API ”简写为“API”)如何设计的文章,然而却没有一个”万能“的设计标准:如何鉴权?API 格式如何?你的 ...

  8. Java [leetcode 1] Two Sum

    小二终于开通博客了,真是高兴.最近在看Java,所以就拿leetcode练练手了.以后我会将自己解体过程中的思路写下来,分享给大家,其中有我自己原创的部分,也有参考别人的代码加入自己理解的部分,希望大 ...

  9. Oracle中job的使用详解

    我们在项目开发中,常常会有一些复杂的业务逻辑.使用oracle的存储过程,可以大大减少java程序代码的编写工作量,而且存储过程执行在数据库上,这样可以利用oracle的良好性能支持,极大地提高程序执 ...

  10. 【转】第一次使用Android Studio时你应该知道的一切配置

    原文网址:http://www.cnblogs.com/smyhvae/p/4390905.html [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.c ...