CF559C Gerald and Giant Chess
阿新 • • 發佈:2020-11-05
給定一個\(n\times m\)(\(n,m\le 10^5\))的棋盤,棋盤上只有\(k\)(\(k\le2000\))個格子是黑色的,其他格子都是白色的。在棋盤左上角有一個卒,每一步可以向右或者向下移動一格,並且不能移動到黑色格子中。求這個卒從左上角移動到右下角,一共有多少種可能的路線。
我們發現\(n,m\)很大,不好下手,所以考慮從\(k\)入手,那麼方案數就是總方案數減去走到這個黑點的方案數乘從這個黑點走到終點的方案數。
總方案數非常好求,就是\(\begin{pmatrix}n+m-2\\n-1\end{pmatrix}\)
然後考慮設\(f_i\)表示從起點走到第\(i\)個黑點且不經過其他黑點的方案數,那麼這個顯然也是可以按剛才那個方法容斥求得的,於是有如下轉移方程:
\(x_i\ge x_j,y_i\ge y_j\)可以通過排序輕鬆處理出來。
於是最後答案就是:
\[\begin{pmatrix}n+m-2\\n-1\end{pmatrix}-\sum_{i=1}^kf_i\begin{pmatrix}n-x_i+m-y_i\\n-x_i\end{pmatrix} \]Code
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> const int N = 2e5; const int p = 1e9 + 7; using namespace std; int n,m,k,fac[N + 5],inv[N + 5],ans,f[N + 5]; struct black { int x,y; }a[N + 5]; int C(int n,int m) { return 1ll * fac[n] * inv[n - m] % p * inv[m] % p; } bool cmp(black a,black b) { if (a.x == b.x) return a.y < b.y; return a.x < b.x; } int main() { scanf("%d%d%d",&n,&m,&k); fac[0] = 1; for (int i = 1;i <= N;i++) fac[i] = 1ll * fac[i - 1] * i % p; inv[1] = 1; for (int i = 2;i <= N;i++) inv[i] = 1ll * (p - p / i) * inv[p % i] % p; inv[0] = 1; for (int i = 1;i <= N;i++) inv[i] = 1ll * inv[i - 1] * inv[i] % p; ans = C(n + m - 2,n - 1); for (int i = 1;i <= k;i++) scanf("%d%d",&a[i].x,&a[i].y); sort(a + 1,a + k + 1,cmp); for (int i = 1;i <= k;i++) { f[i] = C(a[i].x + a[i].y - 2,a[i].x - 1); for (int j = 1;j < i;j++) if (a[j].x <= a[i].x && a[j].y <= a[i].y) f[i] -= 1ll * f[j] * C(a[i].x - a[j].x + a[i].y - a[j].y,a[i].x - a[j].x) % p,f[i] %= p; ans -= 1ll * f[i] * C(n - a[i].x + m - a[i].y,n - a[i].x) % p; ans %= p; } cout<<(ans + p) % p<<endl; return 0; }