[51Nod1486] 大大走格子 (dp+容斥)

传送门

Description

有一个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取余的结果。

Sample Input

3 4 2
2 2
2 3

Sample Output

2

Solution

luogu 4478 上学路线还简单不少

Code

//By Menteur_Hxy
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define F(i,a,b) for(register int i=(a);i<=(b);i++)
#define R(i,a,b) for(register int i=(b);i>=(a);i--)
using namespace std;
typedef long long LL;

inline int read() {
	int x=0,f=1; char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
	while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
	return x*f;
}

const int N=2e5,MAX=2010,MOD=1e9+7;//组合数预处理2e5因为最大是横竖加起来
int n,m,p;
LL fac[N+10],inv[N+10],f[MAX];
struct P{int x,y;}pl[MAX];

LL qpow(LL a,LL b) {
	LL t=1; 
	while(b) {
		if(b&1) t=t*a%MOD;
		a=a*a%MOD; b>>=1;
	}
	return t;
}

void init() {
	fac[0]=1; F(i,1,N) fac[i]=fac[i-1]*i%MOD;
	inv[N]=qpow(fac[N],MOD-2);
	R(i,-1,N-1) inv[i]=inv[i+1]*(LL)(i+1)%MOD;
} 

LL C(int m,int n) {return fac[m]*inv[m-n]%MOD*inv[n]%MOD;}
bool cmp(P a,P b) {return a.x==b.x?a.y<b.y:a.x<b.x;}

int main() {
	init();
	n=read(),m=read(),p=read();
	F(i,1,p) pl[i].x=read(),pl[i].y=read();
	pl[++p].x=n,pl[p].y=m;
	sort(pl+1,pl+1+p,cmp);
	F(i,1,p) f[i]=C(pl[i].x+pl[i].y-2,pl[i].x-1);
	F(i,1,p) F(j,1,i-1) if(pl[j].y<=pl[i].y) {// 一定是小于等于
		LL tmp=C(pl[i].x+pl[i].y-pl[j].x-pl[j].y,pl[i].x-pl[j].x);
		f[i]=(f[i]-f[j]*tmp%MOD+MOD)%MOD;
	}
	printf("%lld",f[p]%MOD);
	return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。 博主:https://www.cnblogs.com/Menteur-Hxy/
原文地址:https://www.cnblogs.com/Menteur-Hxy/p/9620349.html