题目链接:https://vjudge.net/problem/51Nod-1486

题目来源: CodeForces
基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题
 

有一个h行w列的棋盘,里面有一些格子是不能走的,现在要求从左上角走到右下角的方案数。

Input
单组测试数据。
第一行有三个整数h, w, n(1 ≤ h, w ≤ 10^5, 1 ≤ n ≤ 2000),表示棋盘的行和列,还有不能走的格子的数目。
接下来n行描述格子,第i行有两个整数ri, ci (1 ≤ ri ≤ h, 1 ≤ ci ≤ w),表示格子所在的行和列。
输入保证起点和终点不会有不能走的格子。
Output
输出答案对1000000007取余的结果。
Input示例
3 4 2
2 2
2 3
Output示例
2
System Message (题目提供者)

题意:

从(1,1)走到(h,w),只能往下或者往右,且不能走障碍点,问有多少条路线?

题解:

1.可知从(0,0)走到(n,m)有 C(n+m,n)条路径,那么对于一个位于(x,y)的障碍,从(1,1)走到它的位置有C(x+y-2,x-1)条路径。

2.设dp[i]为从(1,1)走到障碍i,且途中不经过任何障碍(除自己外)的路径数。那么怎么求dp[i]呢?

2.1 首先不考虑途中的障碍,那么就有C(x+y-2,x-1)条路径。

2.2 然后再考虑回途中的障碍,如果障碍j满足:x[j]<=x[i] && y[j]<=y[i],那么它就会存在于某些路径当中,即这些路径不合法,需要去除。为了把从(1,1)到障碍i所有不合法的路径删除掉,既不多删也不漏删,就需要一种合理的删除方式:对于一个满足x[j]<=x[i] && y[j]<=y[i] 的障碍j,我们删除以障碍j为路径上第一个障碍的路径,即 dp[j]*C(x[i]-x[j]+y[i]-y[j]-2, x[i]-x[j]-1),然后枚举所有满足条件的障碍j,就正好能够不多不少地把非法路径去除掉。

3. 为了操作方便,把右下角也当成是一个障碍,那么得到的dp[]即为答案。

学习之处:

1.求C[n][m]可以不用O(nm)的时间、空间去预处理,也可以不用O(m)的时间根据公式 C[n][m] = (n-m+1)*C[n][m-1]/m 进行递推。只需先用O(n)的时间预处理出阶乘A[],然后再利用公式:C[n][m] = A[n]/((n-m)!*m!) 以O(1)的时间复杂度求出。

2.按一定的规则或限定去枚举一个合法(非法)对象,并求出其对答案的影响,那么所有合法(非法)对象对答案的影响的并集,即为答案。

代码如下:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int MOD = 1e9+;
const int MAXN = 2e3+; struct node
{
int x, y;
bool operator<(const node &a){
if(x==a.x) return y<a.y;
return x<a.x;
}
}a[MAXN]; LL qpow(LL x, LL y)
{
LL s = ;
while(y)
{
if(y&) s = (s*x)%MOD;
x = (x*x)%MOD;
y >>= ;
}
return s;
} LL A[], inv[]; //预处理出阶乘A[i],以及逆元inv[i],其中inv[i]是A[i]的逆元。
LL C(int n, int m)
{
return (((A[n]*inv[n-m])%MOD)*inv[m])%MOD;
} LL dp[MAXN];
int main()
{
int h, w, n;
A[] = inv[] = ;
for(int i = ; i<; i++) //预处理
{
A[i] = (i*A[i-])%MOD;
inv[i] = qpow(A[i], MOD-);
}
while(scanf("%d%d%d", &h,&w,&n)!=EOF)
{
for(int i = ; i<=n; i++)
scanf("%d%d", &a[i].x, &a[i].y);
a[++n].x = h; a[n].y = w; //把右下角加进去,简化处理
sort(a+,a++n); //按坐标排序
for(int i = ; i<=n; i++)
{
dp[i] = C(a[i].x+a[i].y-, a[i].x-); //初始化
for(int j = ; j<i; j++) //去除不合法的
if(a[i].x>=a[j].x&&a[i].y>=a[j].y)
dp[i] = (dp[i]-(dp[j]*C(a[i].x-a[j].x+a[i].y-a[j].y, a[i].x-a[j].x))%MOD+MOD)%MOD;
}
printf("%lld\n", dp[n]);
}
}

51Nod 1486 大大走格子 —— 组合数学的更多相关文章

  1. 51nod 1486 大大走格子(容斥原理)

    1486 大大走格子 题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题   有一个h行w列的棋盘,里面有一些格子是不能走的,现在要 ...

  2. 51nod 1486 大大走格子(DP+组合数学)

    枚举不合法点的思想. 把障碍x坐标为第一关键字,y坐标为第二关键字排序.f[i]表示走到第i个障碍的方案数. f[i]=C(x[i]+y[i]-2,x[i]-1)-sigma(f[j]*C(x[i]- ...

  3. 51Nod 1486 大大走格子 —— 容斥

    题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1486 对于每个点,求出从起点到它,不经过其他障碍点的方案数: 求一 ...

  4. 51nod 1486 大大走格子——dp

    有一个h行w列的棋盘,里面有一些格子是不能走的,现在要求从左上角走到右下角的方案数. Input 单组测试数据. 第一行有三个整数h, w, n(1 ≤ h, w ≤ 10^5, 1 ≤ n ≤ 20 ...

  5. 51nod 1486 大大走格子——容斥

    题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1486 已知起点到某个障碍点左上角的所有点的不经过障碍的方案数,枚举 ...

  6. 51nod 1486 大大走格子(容斥+dp+组合数)

    传送门 解题思路 暴力容斥复杂度太高,无法接受,考虑用\(dp\).设\(f(i)\)表示从左上角开始不经过前面的阻断点,只经过\(i\)的阻断点.那么可以考虑容斥,用经过\(i\)的总方案数减去前面 ...

  7. 51 Nod 1486 大大走格子

    1486 大大走格子  题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题  收藏  关注 有一个h行w列的棋盘,里面有一些格子是不 ...

  8. 【51NOD】1486 大大走格子

    [算法]动态规划+组合数学 [题意]有一个h行w列的棋盘,定义一些格子为不能走的黑点,现在要求从左上角走到右下角的方案数. [题解] 大概能考虑到离散化黑点后,中间的空格子直接用组合数计算. 然后解决 ...

  9. 51nod 1486

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1486 1486 大大走格子 题目来源: CodeForces 基准时间限 ...

随机推荐

  1. Mycat本地模式的自增长分表操作

    Mycat对表t_rc_rule_monitor做分表操作 在mysql上执行(没有t_rc_rule_monitor) DROP TABLE IF EXISTS t_rc_rule_monitor; ...

  2. python 制作wordcloud词云

    pip install wordcloud 需要用到numpy  pillow matplotlib 安装完成以后 wordcloud_cli --text in.txt --imagefile ou ...

  3. 用循环将三个DIV变成红色

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. Batch update returned unexpected row count from update [0];

    Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested ...

  5. Android--数据库数据显示至屏幕

    MainActivity.java 这段代码的作用是从数据库中获取到数据并显示在界面上 import java.util.ArrayList; import java.util.List; impor ...

  6. 【Python】导入类

    导入单个类 随着不断添加类,可能会使文件变得很长,那么此时,需要将类存储在模块中,然后在主程序导入类即可 book.py class Book(): '''模拟一本书''' def __init__( ...

  7. 重读金典------高质量C编程指南(林锐)-------第一章 文件结构

    第一章  文件结构       C/C++程序通常由两个文件组成,一个文件保存程序的声明,称为头文件,.h 文件.一个保存程序的实现,称为定义文件.c文件. 1.1 版权与版本的声明 版权和版本的声明 ...

  8. wcf上传字节数组报错问题

    为了实现上传大文件所以我们要如下设置最大值,其中security是设置访问服务的认证,此处是把它设置成为不认证,transferMode就是设置运用流的模式 <webHttpBinding> ...

  9. vscode Python Pylint(代码检测插件)

    暑假刚开始想了解一下Python,使用vscode进行编写,根据vscode 的提示安装了一些不知道干啥的插件,编写过程中提示说  "Linter pylint is not install ...

  10. openstack 用nova API 指定 compute node 创建 instance

    感谢朋友支持本博客,欢迎共同探讨交流,因为能力和时间有限,错误之处在所难免,欢迎指正! 假设转载,请保留作者信息. 博客地址:http://blog.csdn.net/qq_21398167 原博文地 ...