我们可以知道,从点(xi,yi)到点(xj,yj)的路径数为\binom{x_j-x_i+y_j-y_i}{x_j-x_i}
不考虑黑白格子的限制,从点\left ( 1,1\right )到(h,w)的路径共有\binom{h+w-2}{h-1}种。
如果存在一个黑格子,那么所有经过当前黑格子到(h,w)的路径都不合法。
考虑两部分,即从(1,1)→(x_i,y_i)与(x_i,y_i)→(h,w)
根据乘法原理,从经过黑格子(x_i,y_i)到(h,w)的总路径为
\binom{x_i+y_i-2}{x_i-1}\times \binom{h-x_i+w-y_i}{h-x_i}
其中要满足x_i≤h,y_i≤w
考虑两个黑格子的情况,(x_i,y_i),(x_j,y_j)其中(x_i,y_i)在(x_j,y_j)的前面。
如果两个格子都像前面那样计算,则会产生重复计数。
即从(x_i,y_i)→(x_j,y_j)→(h,w)的路径会算两次。
如果我们要进行容斥,不同集合的交各不相同,其复杂度是指数级的。
我们考虑(x_j,y_j)的计算
如果我们每次计算黑格子的方案时,都把经过他前面的黑格子的路径给减掉,不就不会产生重复计数了吗?
设f(i)为在不经过前面黑格子到第i个黑格子的方案数。
那么有
ans=\binom{h+w-2}{h-1}-\sum_{i=1}^nf(i)\binom{h-x_i+w-y_i}{h-w_i}
同理对于f(i)有
f(i)=\binom{x_i+y_i-2}{x_i-1}-\sum_{j=1}^{i-1}f(j)\binom{x_i-x_j+y_i-y_j}{x_i-x_j}
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10,M = 2e3 + 10,mod = 1e9 + 7;
typedef pair<int,int> PII;
PII a[M];
int f[M];
int fac[N << 1],invfac[N << 1];
int C(int n,int m){return n<m?0:(long long)fac[n]*invfac[m]%mod*invfac[n-m]%mod;}
void init(){
fac[0]=invfac[0]=invfac[1]=1;
for(int i=1;i<=2e5 + 10;i++)fac[i]=(long long)fac[i-1]*i%mod;
for(int i=2;i<=2e5 + 10;i++)invfac[i]=(long long)(mod-mod/i)*invfac[mod%i]%mod;
for(int i=2;i<=2e5 + 10;i++)invfac[i]=(long long)invfac[i-1]*invfac[i]%mod;
}
int main(){
init();
int h,w,n;
cin >> h >> w >> n;
for (int i = 1; i <= n; i++){
cin >> a[i].first >> a[i].second;
}
sort(a + 1,a + n + 1);
a[n + 1].first = h,a[n + 1].second = w;
for (int i = 1; i <= n + 1; i++){
f[i] = C(a[i].first+a[i].second - 2,a[i].first - 1);
for (int j = 1; j < i; j++){
if (a[j].first > a[i].first || a[j].second > a[i].second) continue;
f[i] = (f[i] - 1ll * f[j] * C(a[i].first-a[j].first+a[i].second-a[j].second,a[i].first-a[j].first) + mod) % mod;
}
}
cout << (f[n + 1] + mod) % mod;
return 0;
}
invfac数组那两行是怎么算的?看不懂
为什么f[n+1]是负数?
因为C里取模了后面再减去了很多乘积项?
请问为什么不考虑黑白格子的限制,从点(1,1)(1,1)到(h,w)的路径共有(h+w−2)! / (h-1)!(w-1)! 种呢
f[n+1]就是(h+w−2)! / (h-1)!(w-1)! - 黑格子的限制