题目链接: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. 2016.7.12 eclispe使用mybatis generator生成代码时提示project E is not exist

    运行mybatis-generator之后,出现错误:project E is not exist   错误原因:使用了项目的绝对路径. http://bbs.csdn.net/topics/3914 ...

  2. crm操作业务部门

    using System;     using System.Linq;     using Microsoft.Xrm.Sdk;     using Microsoft.Crm.Sdk.Messag ...

  3. Codeforces Round #243 (Div. 2)——Sereja and Table

    看这个问题之前,能够先看看这个论文<一类算法复合的方法>,说白了就是分类讨论,可是这个思想非常重要 题目链接 题意: 首先给出联通块的定义:对于相邻(上下和左右)的同样的数字视为一个联通块 ...

  4. 如何在VS2010中添加ActiveX控件及使用方法

    方法1: 1.首先在在项目上面右击添加类,如下图所示: 2.点击添加ActiveX控件中的MFC类 3.找到需要添加的ActiveX类. 4.点击完成即可. 5.此时转到资源视图,打开如下视图.可能工 ...

  5. redis实现訪问频次限制的几种方式

    结合上一篇文章<redis在学生抢房应用中的实践小结>中提及的用redis实现DDOS设计时遇到的expire的坑.事实上,redis官网中对incr命令的介绍中已经有关于怎样用redis ...

  6. x264代码剖析(十三):核心算法之帧间预測函数x264_mb_analyse_inter_*()

    x264代码剖析(十三):核心算法之帧间预測函数x264_mb_analyse_inter_*() 帧间预測是指利用视频时间域相关性,使用临近已编码图像像素预測当前图像的像素,以达到有效去除视频时域冗 ...

  7. Linux内核源码分析方法_转

    Linux内核源码分析方法 转自:http://www.cnblogs.com/fanzhidongyzby/archive/2013/03/20/2970624.html 一.内核源码之我见 Lin ...

  8. 【selenium】Selenium基于Python3的Web自动化测试脚本在IE上运行慢的解决方法

    阐述问题: 执行自动化脚本时,发现文本输入在IE浏览器上特别慢,这样大大降低了自动化效率 解决办法:原因是原先下载的IEDriverServer.exe为64位系统的IE,换为32位的IEDriver ...

  9. Linux下Kafka单机安装配置方法

    Kafka是一个分布式的.可分区的.可复制的消息系统.它提供了普通消息系统的功能,但具有自己独特的设计.这个独特的设计是什么样的呢? 首先让我们看几个基本的消息系统术语: •Kafka将消息以topi ...

  10. ADO.NET Data Service

    关于ADO.NET Entity Framework部分的内容见ADO.NET Entity Framework(1-4) http://www.cnblogs.com/foundation/arch ...