Счёт путей на решётке с запретной клеткой: как вычесть «плохие» пути?
Робот идёт из (0,0) в (W,H) только вправо и вверх. Без препятствий путей C(W+H, W). Но в задаче есть одна заблокированная клетка, через которую идти нельзя. Как посчитать число путей, обходящих эту клетку, по модулю? И как обобщить на несколько препятствий?
2 ответа
Число монотонных путей из (0,0) в (a,b) равно C(a+b, a) — выбираем, на каких из (a+b) шагов идём вправо. Если одна клетка (x,y) запрещена, считаем пути ЧЕРЕЗ неё и вычитаем: путей через (x,y) = C(x+y, x) · C((W−x)+(H−y), W−x). Ответ = C(W+H, W) − (через запретную).
// fact, inv_fact mod p предподсчитаны
long long paths(int a, int b) { // (0,0)->(a,b)
if (a < 0 || b < 0) return 0;
return fact[a+b] * inv_fact[a] % MOD * inv_fact[b] % MOD;
}
long long answerOneBlock(int W, int H, int x, int y) {
long long total = paths(W, H);
long long through = paths(x, y) * paths(W - x, H - y) % MOD;
return (total - through % MOD + MOD) % MOD;
}
Сложность O(1) на запрос. Для НЕСКОЛЬКИХ препятствий простое вычитание ломается (пути через два препятствия вычтутся дважды) — нужно либо включение-исключение, либо, если препятствий немного (≤ k), ДП по препятствиям: отсортировать их по (x+y), и dp[i] = пути до i-го препятствия минус Σ (путей до более раннего j через j). Это O(k^2) и обходит double-counting.
Грабля со знаком: после вычитания по модулю результат может стать отрицательным — обязательно (total - through + MOD) % MOD. И не забывай, что препятствие в самой точке старта или финиша делает ответ нулём — формула это автоматически учитывает, если paths(...) возвращает 0 при выходе за границы. Для отражения от диагонали (пути под прямой) используется отдельная формула Андре — это уже про Каталана.