题目:CF559C.
题目大意:给定一张
n
∗
m
n*m
n∗m的网格,要求从
(
1
,
1
)
(1,1)
(1,1)走到
(
n
,
m
)
(n,m)
(n,m),每次只能往下走一格或往右走一格.现在有
k
k
k个障碍点
(
x
i
,
y
i
)
(x_i,y_i)
(xi,yi),求不经过障碍点的方案数.
1
≤
n
,
m
≤
1
0
5
,
1
≤
k
≤
2000
1\leq n,m\leq 10^5,1\leq k\leq 2000
1≤n,m≤105,1≤k≤2000,答案对
1
0
9
+
7
10^9+7
109+7取模.
首先肯定是个DP,但 n , m n,m n,m过大,不能根据位置直接设计状态.
考虑补集转化,统计所有经过障碍点的方案数.为了不重复统计方案,设
f
[
i
]
f[i]
f[i]表示到第一次经过障碍点时第
i
i
i个的方案数,显然转移方程为:
f
[
i
]
=
(
x
i
+
y
i
−
2
x
i
−
1
)
−
∑
i
=
̸
j
∧
x
j
≤
x
i
∧
y
j
≤
y
i
(
x
i
+
y
i
−
x
j
−
y
j
x
i
−
x
j
)
f
[
j
]
f[i]=\binom{x_i+y_i-2}{x_i-1}-\sum_{i=\not{}j\wedge x_j\leq x_i\wedge y_j\leq y_i}\binom{x_i+y_i-x_j-y_j}{x_i-x_j}f[j]
f[i]=(xi−1xi+yi−2)−i≠j∧xj≤xi∧yj≤yi∑(xi−xjxi+yi−xj−yj)f[j]
时间复杂度 O ( n 2 ) O(n^2) O(n2).
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=2000,M=100000,mod=1000000007;
int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
int sub(int a,int b){return a-b<0?a-b+mod:a-b;}
int mul(int a,int b){return (LL)a*b%mod;}
void sadd(int &a,int b){a=add(a,b);}
void ssub(int &a,int b){a=sub(a,b);}
void smul(int &a,int b){a=mul(a,b);}
int n;
struct point{
int x,y;
}a[N+9];
bool cmp(const point &a,const point &b){return a.x<b.x||a.x==b.x&&a.y<b.y;}
int inv[M*2+9],fac[M*2+9],ifac[M*2+9];
void Get_inv(){
int m=a[n].x+a[n].y;
inv[1]=1;
fac[0]=fac[1]=1;
ifac[0]=ifac[1]=1;
for (int i=2;i<=m;++i){
inv[i]=mul(mod-mod/i,inv[mod%i]);
fac[i]=mul(fac[i-1],i);
ifac[i]=mul(ifac[i-1],inv[i]);
}
}
int Get_c(int n,int m){return mul(fac[n],mul(ifac[m],ifac[n-m]));}
int dp[N+9];
void Get_dp(){
dp[0]=1;
for (int i=1;i<=n;++i){
dp[i]=Get_c(a[i].x+a[i].y-2,a[i].x-1);
for (int j=1;j<i;++j)
if (a[j].y<=a[i].y)
ssub(dp[i],mul(dp[j],Get_c(a[i].x+a[i].y-a[j].x-a[j].y,a[i].x-a[j].x)));
}
}
Abigail into(){
int x,y;
scanf("%d%d%d",&x,&y,&n);
a[n+1].x=x;a[n+1].y=y;
for (int i=1;i<=n;++i)
scanf("%d%d",&a[i].x,&a[i].y);
}
Abigail work(){
a[0].x=1;a[0].y=1;
sort(a+1,a+n+1,cmp);
++n;
Get_inv();
Get_dp();
}
Abigail outo(){
printf("%d\n",dp[n]);
}
int main(){
into();
work();
outo();
return 0;
}