AOJ 2397 Three-way Branch
問題
Three-way Branch | Aizu Online Judge
W*H のグリッドが与えられる。これらのうち, N 個のセルは通れなくなっている。あるセル(x, y) からは (x-1, y+1) or (x, y+1) or (x+1, y+1) にのみ行ける場合, (0, 0) から (W-1, H-1) までの経路は何通りあるか。
解法
W がまぁまぁ小さくて H が超でかいので行列累乗な感じがします。
障害物は N 個しかないので,
- 障害物のある行になるまでは行列累乗
- 障害物ある行では 対応するところの場合の数を 0 にする
というようにやれば O(W^3 log H * N) でできます。…結構ギリギリですが。
typedef long long number; typedef vector<number> vec; typedef vector<vec> matrix; const int MOD = 1e9+9; // O( n ) matrix Identity(int n) { matrix A(n, vec(n)); for (int i = 0; i < n; ++i) A[i][i] = 1; return A; } // O( n^3 ) matrix mul(const matrix &A, const matrix &B) { matrix C(A.size(), vec(B[0].size())); for (int i = 0; i < (int)C.size(); ++i) for (int j = 0; j < (int)C[i].size(); ++j) for (int k = 0; k < (int)A[i].size(); ++k) { C[i][j] += A[i][k] * B[k][j]; C[i][j] %= MOD; } return C; } // O( n^3 log e ) matrix pow(const matrix &A, ll e) { if (e == 0) return Identity(A.size()); if (e == 1) return A; if (e % 2 == 0) { matrix tmp = pow(A, e/2); return mul(tmp, tmp); } else { matrix tmp = pow(A, e-1); return mul(A, tmp); } } // O(n) number tr(const matrix &A) { number ans = 0; for (int i = 0; i < (int)A.size(); ++i) ans += A[i][i]; return ans; } // O( n ) number inner_product(const vec &a, const vec &b) { number ans = 0; for (int i = 0; i < (int)a.size(); ++i) ans += a[i] * b[i]; return ans; } // O( n^2 ) vec mul(const matrix &A, const vec &x) { vec y(A.size()); for (int i = 0; i < (int)A.size(); ++i) for (int j = 0; j < (int)A[0].size(); ++j) (y[i] += (A[i][j] * x[j] % MOD)) %= MOD; return y; } const int MAXN = 33; int W, N; ll H; ll solve() { vector<pair<ll, int> > P(N); for (int i = 0; i < N; i++) { cin >> P[i].second >> P[i].first; P[i].first--; P[i].second--; } sort(P.begin(), P.end()); vec v(W); v[0] = 1; ll now = 0; for (int i = 0; i < N; ) { matrix mat(W, vec(W)); for (int j = 0; j < W; j++) { if (j-1 >= 0) mat[j][j-1] = 1; mat[j][j] = 1; if (j+1 < W) mat[j][j+1] = 1; } v = mul(pow(mat, P[i].first-now), v); now = P[i].first; int ni = i; while (ni < N && P[i].first == P[ni].first) ni++; for (int j = i; j < ni; j++) v[P[j].second] = 0; i = ni; } matrix mat(W, vec(W)); for (int i = 0; i < W; i++) { if (i-1 >= 0) mat[i][i-1] = 1; mat[i][i] = 1; if (i+1 < W) mat[i][i+1] = 1; } v = mul(pow(mat, H-1-now), v); return v[W-1]; } int main() { cin.tie(0); ios::sync_with_stdio(false); for (int t = 1; ; t++) { cin >> W >> H >> N; if (W == 0) break; cout << "Case " << t << ": " << solve() << endl; } return 0; }