cf559 C. Gerald and Giant Chess(dp+組合數)
阿新 • • 發佈:2022-03-06
題意:
n*m網格,其中有k個網格中有障礙物不能走。每步只能往下或往右求從左上走到右下的路徑數。
\(1\le n,m\le 1e5,1\le k \le 2000\)
思路:
網格總數很大,但是障礙物很少,顯然複雜度跟障礙數有關。
一開始想的是容斥:所有路徑數 - 經過至少一個障礙的路徑數 + 經過至少兩個障礙的路徑數 - …… ,然後就暈了
正解:對所有障礙物排序,\(dp(i)\) 表示從左上走到第 \(i\) 個障礙物,中間不經過任何一個障礙物的路徑數
怎麼計算 \(dp(i)\) 呢?可以把從左上走到第 \(i\) 個障礙物的路徑這樣分類:不經過任何一個障礙物的、路徑上第一個障礙物的序號為1、路徑上的第一個障礙物為2、……
那麼 \(dp(i)=C_{x_i-1+y_i-1}^{x_i-1}-\sum\limits _{會影響到i的j} dp(j)*C_{x_i-x_j+y_i-y_j}^{x_i-x_j}\)
為方便,增加一個位於終點的障礙物。
ll del(ll x, ll y) { return x-y<0?x-y+MOD:x-y; } main() { iofast; cin >> n >> m >> k; for(int i = 1; i <= k; i++) cin >> a[i].fi >> a[i].se; init(); //預處理階乘和逆元 sort(a + 1, a + 1 + k); a[++k] = {n,m}; for(int i = 1; i <= k; i++) { ll x = a[i].fi, y = a[i].se; for(int j = 1; j < i; j++) if(a[j].fi <= x && a[j].se <= y) (dp[i] += dp[j] * C(x-a[j].fi+y-a[j].se,x-a[j].fi) % MOD) %= MOD; dp[i] = del( C(x-1+y-1,x-1) , dp[i]); } cout << dp[k]; }