AT_dp_y Grid 2题解

题目描述

有一个高为 H 行、宽为 W 列的网格。我们用 (i,j) 表示从上往下第 i 行、从左往右第 j 列的格子。

在这个网格中,有 N 个格子 (r1​,c1​), (r2​,c2​), …, (rN​,cN​) 是墙,其余的格子都是空格子。保证格子 (1,1) 和 (H,W) 都是空格子。

太郎君从格子 (1,1) 出发,每次只能向右或向下移动到相邻的空格子,他想要到达格子 (H,W)。

请问,从 (1,1) 到 (H,W) 的路径有多少种?请输出答案对 109+7 取模的结果。

输入格式

输入通过标准输入给出,格式如下:

H W N r1​ c1​ r2​ c2​ … rN​ cN​

输出格式

输出从 (1,1) 到 (H,W) 的路径数,对 109+7 取模。

显示翻译

题意翻译

输入输出样例

输入 #1复制

3 4 2
2 2
1 4

输出 #1复制

3

输入 #2复制

5 2 2
2 1
4 2

输出 #2复制

0

输入 #3复制

5 5 4
3 1
3 5
1 3
5 3

输出 #3复制

24

输入 #4复制

100000 100000 1
50000 50000

输出 #4复制

123445622

说明/提示

限制条件

  • 所有输入均为整数。
  • 2≤H,W≤105
  • 1≤N≤3000
  • 1≤ri​≤H
  • 1≤ci​≤W
  • 所有 (ri​,ci​) 互不相同。
  • (1,1) 和 (H,W) 都是空格子。

样例解释 1

路径共有如下图的 3 种。

样例解释 2

也有可能不存在任何路径。

样例解释 4

不要忘记输出答案时要对 109+7 取模。

由 ChatGPT 4.1 翻译

思路

DP即可。

代码见下

#include<bits/stdc++.h>
using namespace std;
struct one{
	long long r,c;
}a[3005];
long long n,h,w,f[3005],ff[900005],fn[900005],fc[900005],mod=1e9+7;
bool cmp(one a1,one b1){
	if(a1.r!=b1.r) return a1.r<b1.r;
	else return a1.c<b1.c;
}
long long qupow(long long a,long long b,long long p){
	long long s=1;
	while(b){
		if(b%2==1) s=(a*s)%p;
		a*=a;
		b/=2;
		a%=p;
	}
	return s;
}
long long cc(long long x,long long y){
	return (ff[x]*fc[y]%mod)*fc[x-y]%mod;
}
int main(){
	cin>>h>>w>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i].r>>a[i].c;
	}
	a[++n].r=h;
	a[n].c=w;
	sort(a+1,a+n+1,cmp);
	ff[0]=1;
	for(int i=1;i<=900000;i++){
		ff[i]=(ff[i-1]*i)%mod;
		//cout<<i<<" "<<ff[i]<<endl;
	}
	fn[0]=fn[1]=1;
	for(int i=2;i<=900000;i++){
		fn[i]=((mod-mod/i)*fn[mod%i]+mod*300000)%mod;
		//cout<<i<<" "<<fn[i]<<endl;
	}
	fc[0]=1;
	for(int i=1;i<=900000;i++){
		fc[i]=(fc[i-1]*fn[i])%mod;
	}	
	for(int i=1;i<=n;i++){
		f[i]=cc(a[i].r+a[i].c-2,a[i].r-1);
		//cout<<i<<" "<<f[i]<<endl;
		for(int j=1;j<=i-1;j++){
			if(a[j].r<=a[i].r&&a[j].c<=a[i].c){
				f[i]=(f[i]-f[j]*cc(a[i].r+a[i].c-a[j].r-a[j].c,a[i].r-a[j].r)+mod*mod)%mod;
			}
		}
	}	
	cout<<(f[n]+mod)%mod<<endl;
	return 0;
}

posted @ 2025-10-23 10:43  bz02_2023f2  阅读(3)  评论(0)    收藏  举报  来源