1. 程式人生 > >Luogu 4159 [SCOI2009]迷路

Luogu 4159 [SCOI2009]迷路

BZOJ 1297

應當是簡單題。

發現邊權的數量很小,所以我們暴力把一個點拆成$9$個點,然後把$(x, i)$到$(x, i + 1)$連邊,代表轉移一次之後可以走回來;對於每一條存在的邊$(i, j, k)$,把$(i, k)$向$(j, 1)$連邊,代表走一條路。然後用這個矩陣乘$T$次即可,這樣子最後的答案$ans = [(1, 1)][(n, 1)]$格子的值。

記$m = 9 * n$,時間複雜度為$O(m^3logT)$。

Code:

#include <cstdio>
#include <cstring>
using
namespace std; const int N = 15; const int M = 105; const int P = 2009; int n, tim; inline void inc(int &x, int y) { x += y; if(x >= P) x -= P; } inline int id(int x, int k) { return (x - 1) * 9 + k; } struct Matrix { int len, wid, s[M][M]; inline void
init(int r, int c) { len = r, wid = c; memset(s, 0, sizeof(s)); } friend Matrix operator * (const Matrix &x, const Matrix &y) { Matrix res; res.init(x.len, y.wid); for(int k = 1; k <= x.wid; k++) for(int i = 1; i <= x.len; i++)
for(int j = 1; j <= y.wid; j++) inc(res.s[i][j], x.s[i][k] * y.s[k][j] % P); return res; } inline void print() { for(int i = 1; i <= len; i++, printf("\n")) for(int j = 1; j <= wid; j++) printf("%d ", s[i][j]); } } f; inline Matrix fpow(Matrix x, int y) { Matrix res; res.init(x.len, x.wid); for(int i = 1; i <= x.len; i++) res.s[i][i] = 1; for(; y > 0; y >>= 1) { if(y & 1) res = res * x; x = x * x; } return res; } int main() { scanf("%d%d", &n, &tim); f.init(9 * n, 9 * n); for(int i = 1; i <= n; i++) { char str[N]; scanf("%s", str + 1); for(int j = 1; j <= n; j++) { int k = str[j] - '0'; if(!k) continue; f.s[id(i, k)][id(j, 1)] = 1; } for(int j = 2; j <= 9; j++) f.s[id(i, j - 1)][id(i, j)] = 1; } // f.print(); f = fpow(f, tim); // f.print(); printf("%d\n", f.s[id(1, 1)][id(n, 1)]); return 0; }
View Code