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

题意:让一个棋子从(1,1)走到(n,m),要求像马一样走日字型并只能往右下角走。里面还有r个障碍点不能经过或者到达,问有多少种走法可以走到(n,m)。

思路:画个图可以发现走的点像一个斜着的杨辉三角。所以可以得到一个从点 i 走到点 j 的路径数是一个组合数。

大概就是长这样,杨辉三角的每个点的数如下。

1

1       1

1      2      1

1       3      3      1

1      4       6      4      1

1       5      10      10      5      1

1      6      15      20      15      6      1

1      7      21      35      35      21      7      1

找到规律:路径数为C(在这一步的位置,走过的步数)。走过的步数是当前的点 i 坐标(x,y),(x+y)/3就是步数了。当前的位置是min(x,y)-步数。这里的步数就相当于三角的层数。

首先对全部障碍从小到大进行排序,对于每个障碍 i,求出从(1,1)走到其的路径总数,减去之前的障碍(0 <= j < i)可以走到现在的障碍的路径总数(dp[i] -= dp[j] * 从点 j 走到点 i 的路径数)。组合数的计算要用到Lucas定理进行计算。

 #include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <iostream>
#include <stack>
using namespace std;
#define MOD 110119
typedef long long LL;
struct node
{
LL x, y;
}p[];
LL dp[];
LL f[MOD+];
/*
dp[i]一开始表示从(0, 0)走到第i个点的路径数
后面要减去如果前面有障碍,那么会有一部分路径是不能走的
减去的路径数为分别为第j个点(0<=j<i)走到第i个点的路径数*dp[j]
*/ bool cmp(const node &a, const node &b)
{
if(a.x == b.x) return a.y < b.y;
return a.x < b.x;
} void biao() //打出阶乘表
{
f[] = f[] = ;
for(int i = ; i <= MOD; i++) {
f[i] = f[i-] * i % MOD;
}
} LL quick_pow(LL a, LL b)
{
a %= MOD, b %= MOD;
LL ans = ;
while(b) {
if(b & ) ans = ans * a % MOD;
a = a * a % MOD;
b >>= ;
}
return ans;
} LL C(LL n, LL m)
{
if(m > n) return ;
if(m < ) return ;
LL ans = ;
ans = ans * f[n] % MOD * quick_pow(f[m] * f[n-m] % MOD, MOD - ) % MOD;
return ans;
} LL Lucas(LL n, LL m)
{
if(m == ) return ;
return C(n % MOD, m % MOD) % MOD * Lucas(n / MOD, m / MOD) % MOD;
} int main()
{
LL n, m, r;
int cas = ;
biao();
while(~scanf("%I64d%I64d%I64d", &n, &m, &r)) {
memset(dp, , sizeof(dp));
bool flag = ;
for(int i = ; i < r; i++) {
scanf("%I64d%I64d", &p[i].x, &p[i].y);
if(p[i].x == n && p[i].y == m) flag = ;
p[i].x--, p[i].y--;
}
sort(p, p + r, cmp);
p[r].x = n - , p[r].y = m - ; //把目标点加入
printf("Case #%d: ", ++cas);
if(flag || (p[r].x + p[r].y) % != ) { //如果障碍在目标点上或者不能走到目标点
puts(""); continue;
}
for(int i = ; i <= r; i++) {
if((p[i].x + p[i].y) % == ) { //如果这个障碍是可以走到的
LL a = (p[i].x + p[i].y) / ; //第几层
LL b = min(p[i].x, p[i].y) - a; //位置
dp[i] = Lucas(a, b); //类似于杨辉三角的组合数
for(int j = ; j < i; j++) {
if(p[j].y >= p[i].y || p[j].x >= p[i].x) continue; //题目要求只能往右下角走
LL xx = (p[i].x - p[j].x);
LL yy = (p[i].y - p[j].y);
if((xx + yy) % == ) { //要能够从j点走到i点
LL aa = (xx + yy) / ;
LL bb = min(xx, yy) - aa; //减去可以从j点走到i点的路径数
dp[i] -= (Lucas(aa, bb) * dp[j]) % MOD;
dp[i] = (dp[i] + MOD) % MOD;
}
}
}
}
printf("%I64d\n", dp[r]);
}
return ;
}

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

  1. HDU 3076:ssworld VS DDD(概率DP)

    http://acm.split.hdu.edu.cn/showproblem.php?pid=3076 ssworld VS DDD Problem Description   One day, s ...

  2. HDU 5616:Jam's balance(背包DP)

    http://acm.hdu.edu.cn/showproblem.php?pid=5616 题意:有n个物品,每个重量为w[i],有一个天平,你可以把物品放在天平的左边或者右边,接下来m个询问,问是 ...

  3. 【HDU 5647】DZY Loves Connecting(树DP)

    pid=5647">[HDU 5647]DZY Loves Connecting(树DP) DZY Loves Connecting Time Limit: 4000/2000 MS ...

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

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

  5. HDU 5795:A Simple Nim(博弈)

    http://acm.hdu.edu.cn/showproblem.php?pid=5795 A Simple Nim Problem Description   Two players take t ...

  6. HDU 4315:Climbing the Hill(阶梯博弈)

    http://acm.hdu.edu.cn/showproblem.php?pid=4315 题意:有n个人要往坐标为0的地方移动,他们分别有一个位置a[i],其中最靠近0的第k个人是king,移动的 ...

  7. HDU 6215:Brute Force Sorting(链表+队列)

    题目链接 题意 给出一个长度为n的数组,每次操作都要删除数组里面非递增的元素,问最终的数组元素有什么. 思路 容易想到用链表模拟删除,但是不能每次都暴力枚举,这样复杂度O(N^2).想到每次删除元素的 ...

  8. UVA-11584:Partitioning by Palindromes(基础DP)

    今天带来一个简单的线性结构上的DP,与上次的照明系统(UVA11400)是同一种类型题,便于大家类比.总结.理解,但难度上降低了. We say a sequence of characters is ...

  9. Codeforces Gym100623J:Just Too Lucky(数位DP)

    http://codeforces.com/gym/100623/attachments 题意:问1到n里面有多少个数满足:本身被其各个数位加起来的和整除.例如120 % 3 == 0,111 % 3 ...

随机推荐

  1. java类的加载、链接、初始化

    JVM和类的关系 当我们调用JAVA命令运行某个java程序时,该命令将会启动一条java虚拟机进程,不管该java程序有多么复杂,该程序启动了多少个线程,它们都处于该java虚拟机进程里.正如前面介 ...

  2. Silverlight/WPF绘制统计图Visifire.dll文件

    官网:http://www.visifire.com/ 一直没找到好的中文文档,希望有的这个的可以发个我! 效果图: 前台代码: <UserControl x:Class="Text_ ...

  3. ARC机制集合内存管理

    // //  main.m //  13-ARC机制集合内存管理 // //  Created by apple on 14-3-21. //  Copyright (c) 2014年 apple. ...

  4. lua对模块接口扩展的一种方法

    module lua中模块的实现,对于使用者来说就是一个库,引用此库后,可以调用库中实现的任意函数. 使用库,可以将一类功能相关的接口做封装,并提供开放接口. 参考: http://blog.codi ...

  5. Excel将秒转换成标准的时间格式HH:MM:SS

    Excel将秒转换成标准的时间格式HH:MM:SS 比如120秒,转换成00:02:00 Excel公式为: =TEXT(A1/86400,"[hh]:mm:ss") A1为秒数据 ...

  6. Java基础之一组有用的类——使用正则表达式搜索子字符串(TryRegex)

    控制台程序. 正则表达式只是一个字符串,描述了在其他字符串中搜索匹配的模式.但这不是被动地进行字符序列匹配,正则表达式其实是一个微型程序,用于一种特殊的计算机——状态机.状态机并不是真正的机器,而是软 ...

  7. Java基础之写文件——使用带缓冲的Writer写文件(WriterOutputToFile)

    控制台程序,将一列字符串写入到文件中. import java.io.*; import java.nio.file.*; import java.nio.charset.Charset; publi ...

  8. tomcat部署方法总结

    可以参考之前的:http://www.cnblogs.com/youxin/archive/2013/01/18/2865814.html 在Tomcat中部署Java Web应用程序有两种方式:静态 ...

  9. acm算法模板(2)

    数学问题: 1.精度计算——大数阶乘 2.精度计算——乘法(大数乘小数) 3.精度计算——乘法(大数乘大数) 4.精度计算——加法 5.精度计算——减法 6.任意进制转换 7.最大公约数.最小公倍数 ...

  10. maven的pom报plugins却是的解决方法(转)

    maven的pom报plugins却是的解决方法. 引用 Failure to transfer org.apache.maven.plugins:maven-surefire-plugin:pom: ...