Solution
- dp[i] 表示走到第i障碍物的合法方案数
- 走到点(x, y)的所有方案数: C ( x + y − 2 , x − 1 ) C(x + y - 2, x - 1) C(x+y−2,x−1)
-
d
p
[
i
]
=
C
(
i
.
x
+
i
.
y
−
2
,
i
.
x
−
1
)
−
∑
d
p
[
j
]
∗
C
(
i
.
x
−
j
.
x
+
i
.
y
−
j
.
y
,
i
.
x
−
j
.
x
)
dp[i] = C(i.x + i.y - 2, i.x - 1) - \sum dp[j] * C(i.x - j.x + i.y - j.y, i.x - j.x)
dp[i]=C(i.x+i.y−2,i.x−1)−∑dp[j]∗C(i.x−j.x+i.y−j.y,i.x−j.x)
即:合法方案数 = 所有方案数 - 所有非法的方案数
Code
const ll mod = 1000000007;
using namespace std;
const int N = 2e6 + 5;
ll f[N];
ll inv[N], fac[N];
void init()
{
fac[0] = inv[1] = inv[0] = 1;
//注意:inv[0] = 1, 即零的阶乘的逆元为1
for (int i = 1; i <= 2e6; i++)
fac[i] = fac[i - 1] * i % mod;
//先求出1~n的逆元
for (int i = 2; i <= 2e6; i++)
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
//1~n的逆元累成即为 1~n的阶乘的逆元
for (int i = 2; i <= 2e6; i++)
inv[i] = inv[i] * inv[i - 1] % mod;
}
ll C(int n, int m)
{
return fac[n] * inv[n - m] % mod * inv[m] % mod;
}
pii s[N];
int main()
{
IOS;
init();
int n, m; cin >> n >> m;
for (int i = 1; i <= m; i++)
cin >> s[i].ft >> s[i].sd;
sort(s + 1, s + m + 1);//注意对障碍物排序
s[m + 1] = { n, n };
for (int i = 1; i <= m + 1; i++)
{
f[i] = C(s[i].ft + s[i].sd - 2, s[i].ft - 1);
for (int j = 1; j < i; j++)
{
//注意:只减去 s[j].ft <= s[i].ft && s[j].sd <= s[i].sd的方案
if (s[j].sd > s[i].sd) continue;
ll t = C(s[i].ft - s[j].ft + s[i].sd - s[j].sd, s[i].ft - s[j].ft);
f[i] = ((f[i] - f[j] * t % mod) % mod + mod) % mod;
}
}
cout << f[m + 1];
return 0;
}