【bzoj1297】[SCOI2009]迷路 矩陣乘法
阿新 • • 發佈:2018-01-17
時間復雜度 brush 時間 col 表示 data 接下來 con pan
題目描述
給出一個 $n$ 個點的有向圖,每條邊的權值都在 $[1,9]$ 之間。給出 $t$ ,求從 $1$ 到 $n$ ,經過路徑邊權和恰好為 $t$ 的方案數模2009。
輸入
第一行包含兩個整數,N T。 接下來有 N 行,每行一個長度為 N 的字符串。 第i行第j列為‘0‘表示從節點i到節點j沒有邊。 為‘1‘到‘9‘表示從節點i到節點j需要耗費的時間。
輸出
包含一個整數,可能的路徑數,這個數可能很大,只需輸出這個數除以2009的余數。
樣例輸入
5 30
12045
07105
47805
12024
12345
樣例輸出
852
題解
矩陣乘法
傻題,顯然如果沒有邊權的話就是裸的矩乘。如果有邊權的話,拆邊的話點數為 $9m$ 的,難以接受。
考慮拆點,將1個點拆成9個連成鏈,每次將出點對應邊權的點連到入點上。這樣點數就是 $9n$ 了。
時間復雜度 $O((9n)^3)$
#include <cstdio> #include <cstring> char str[15]; int m; struct data { int v[100][100]; data() {memset(v , 0 , sizeof(v));} int *operator[](int a) {return v[a];} data operator*(data &a) { data ans; int i , j , k; for(i = 0 ; i < m ; i ++ ) for(j = 0 ; j < m ; j ++ ) for(k = 0 ; k < m ; k ++ ) ans[i][j] = (ans[i][j] + v[i][k] * a[k][j]) % 2009; return ans; } }A; data pow(data x , int y) { data ans; int i; for(i = 0 ; i < m ; i ++ ) ans[i][i] = 1; while(y) { if(y & 1) ans = ans * x; x = x * x , y >>= 1; } return ans; } int main() { int n , k , i , j; scanf("%d%d" , &n , &k) , m = n * 9; for(i = 0 ; i < n ; i ++ ) { scanf("%s" , str); for(j = 0 ; j < 8 ; j ++ ) A[i * 9 + j][i * 9 + j + 1] = 1; for(j = 0 ; j < n ; j ++ ) if(str[j] != ‘0‘) A[i * 9 + str[j] - ‘1‘][j * 9] = 1; } printf("%d\n" , pow(A , k)[0][n * 9 - 9]); return 0; }
【bzoj1297】[SCOI2009]迷路 矩陣乘法