BZOJ1297 [SCOI2009]迷路
阿新 • • 發佈:2017-06-16
$$ 一個 如果 線性 con std bzoj turn ont
【輸入樣例一】
2 2
11
00
【輸入樣例二】
5 30
12045
07105
47805
12024
12345
1
【樣例解釋一】
0->0->1
【輸出樣例二】
852
Description
windy在有向圖中迷路了。 該有向圖有 N 個節點,windy從節點 0 出發,他必須恰好在 T 時刻到達節點 N-1。 現在給出該有向圖,你能告訴windy總共有多少種不同的路徑嗎? 註意:windy不能在某個節點逗留,且通過某有向邊的時間嚴格為給定的時間。
Input
第一行包含兩個整數,N T。 接下來有 N 行,每行一個長度為 N 的字符串。 第i行第j列為‘0‘表示從節點i到節點j沒有邊。 為‘1‘到‘9‘表示從節點i到節點j需要耗費的時間。
Output
包含一個整數,可能的路徑數,這個數可能很大,只需輸出這個數除以2009的余數。
Sample Input
2 2
11
00
【輸入樣例二】
5 30
12045
07105
47805
12024
12345
Sample Output
【輸出樣例一】1
【樣例解釋一】
0->0->1
【輸出樣例二】
852
HINT
30%的數據,滿足 2 <= N <= 5 ; 1 <= T <= 30 。 100%的數據,滿足 2 <= N <= 10 ; 1 <= T <= 1000000000 。
題解
令鄰接矩陣中所有k組成的矩陣為$A_k$,$i$階鄰接矩陣為$T_i$,即$T_{i,a,b}$表示從$a$到$b$恰好走$i$的時間的方案數。
那麽有
$$T_i = \sum_{j=1}^9 A_j * T_{i-j}$$
我們發現,如果我們把$A_j$和$T_i$都看做單個數,那麽這就是經典的線性常系數遞推方程,可以用矩陣快速冪解決。
$A_j,T_i$是矩陣也可以這麽做,只是1變成了單位矩陣,0變成了零矩陣,遞推矩陣變成了“矩陣的矩陣”(當然,在實現上,我們可以把它“拍扁”)。
那麽直接強上矩陣快速冪就行了。
附代碼:
#include <cstdio> #include <cstring> const int N = 15; const int mod = 2009; int nn; struct Matrix{ int v[N * 9][N * 9]; Matrix() { memset(v, 0, sizeof v); } friend Matrix operator*(const Matrix &a, const Matrix &b) { Matrix ans; for (int i = 0; i < nn; ++i) for (int j = 0; j < nn; ++j) if (a.v[i][j]) for (int k = 0; k < nn; ++k) ans.v[i][k] = (ans.v[i][k] + a.v[i][j] * b.v[j][k]) % mod; return ans; } }; Matrix D; Matrix ans; int main() { int n, t; scanf("%d%d", &n, &t); nn = n * 9; int x; for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) { scanf("%1d", &x); if (x) D.v[i][(x - 1) * n + j] = 1; } for (int i = 0; i < 8 * n; ++i) D.v[i + n][i] = 1; for (int i = 0; i < n; ++i) ans.v[i][i] = 1; for (; t; D = D * D, t >>= 1) if (t & 1) ans = ans * D; printf("%d\n", ans.v[0][n - 1]); return 0; }
BZOJ1297 [SCOI2009]迷路