路径计数2
题目链接
题意
有一个
n
?
n
n?n
n?n 的网格,有些格子是可以通行的,还有
m
m
m 个格子是障碍。 一开始你在左上角的位置,你可以每一步往下或者往右走,问有多少种走到右下角的方案。 由于答案很大,输出对
1
0
9
10^9
109+7 取模的结果。
思路 | 组合数
因为
n
n
n 的量级有点大,原来的
d
p
dp
dp 正向求一共有多少条路是不行的。现在的话就要求总路径的条数减去不能通行的路径数量。 假设从A到B的路径中没有障碍点,那么从A到B的路径数是组合数
C
(
x
+
y
,
x
)
C(x+y,x)
C(x+y,x)
为了能够递推,要将障碍点按行再列优先进行排序,然后考虑在枚举到第
j
j
j 个点的时候 枚举前
j
?
1
j-1
j?1 个点,看看他们是否在从 1 到
j
j
j 的路径上 如果在的话就要减去这个值
d
p
j
dp_j
dpj? =
C
x
j
+
y
j
?
2
x
j
?
1
C^{x_{j}-1}_{x_j+y_j -2}
Cxj?+yj??2xj??1? -
∑
i
=
1
j
?
1
\displaystyle \sum^{j-1}_{i = 1}
i=1∑j?1?
d
p
i
dp_i
dpi?
×
\times
×
C
x
j
+
y
j
?
x
i
?
y
j
x
j
?
x
i
C^{x_{j}-x_{i}}_{x_j+y_j -x_{i}-y_{j}}
Cxj?+yj??xi??yj?xj??xi??
代码
#include <stdio.h>
#include <cstdio>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <cmath>
#include <vector>
#include <algorithm>
#include <set>
#include <iostream>
using namespace std;
#define int long long
const int maxn=2e6+10;
const int p=1e9+7;
int n,m;
struct node{int x,y;}a[maxn];
int c[maxn],sum[maxn];
void init(){ c[0]=1; for(int i=1;i<=2000002;i++) c[i]=c[i-1]*i%p;}
bool cmp(node a,node b) {if(a.x!=b.x)return a.x<b.x;return a.y<b.y;}
bool check(node a,node b){if(a.x<=b.x&&a.y<=b.y) return 1;return 0;}
int ksm(int a, int b) { int ans = 1;while (b > 0) {if (b & 1)ans = (ans * a) % p;b >>= 1;a = (a * a) % p;}return ans;}
int C(int n,int k) {return c[n]*ksm(c[n-k]*c[k]%p,p-2)%p;}
void solve(){
cin>>n>>m;
for(int i=1;i<=m;i++)cin>>a[i].x>>a[i].y;
a[++m].x=n;a[m].y=n;
sort(a+1,a+1+m,cmp);
for(int i=1;i<=m;i++){
sum[i]=C(a[i].x+a[i].y-2,a[i].x-1);
for(int j=1;j<i;j++){
if(check(a[j],a[i])){
sum[i]=(sum[i]-sum[j]*C(a[i].x-a[j].x+a[i].y-a[j].y,a[i].x-a[j].x)%p+p)%p;
}
}
}
cout<<sum[m]<<endl;
}
signed main(){
int t=1;
init();
while(t--) solve();
return 0;
}
|