bzoj 1875 [SDOI2009]HH去散步 矩陣乘法
阿新 • • 發佈:2018-08-14
不能 ack read class for har ans sin clear
題面
題目傳送門
解法
如果沒有不能經過上一次經過的邊這個限制,顯然就是矩陣乘法的裸題
那麽我們考慮轉化一下,把邊當成點
將一條無向邊拆成2條有向邊,然後連邊,設鄰接矩陣為\(A\)
將\(A\)變成\(A^{T-1}\),然後枚舉起點的出邊,終點的入邊即可
時間復雜度:\(O(m^3\ log\ T)\)
代碼
#include <bits/stdc++.h> #define Mod 45989 #define N 150 using namespace std; template <typename node> void chkmax(node &x, node y) {x = max(x, y);} template <typename node> void chkmin(node &x, node y) {x = min(x, y);} template <typename node> void read(node &x) { x = 0; int f = 1; char c = getchar(); while (!isdigit(c)) {if (c == ‘-‘) f = -1; c = getchar();} while (isdigit(c)) x = x * 10 + c - ‘0‘, c = getchar(); x *= f; } struct Node { int x, y; } a[N]; struct Matrix { int a[N][N]; void Clear() {memset(a, 0, sizeof(a));} }; int n, m, T, s, t, tot, cnt; vector <int> e[N]; Matrix operator * (Matrix x, Matrix y) { Matrix ret; ret.Clear(); for (int k = 2; k <= tot; k++) for (int i = 2; i <= tot; i++) for (int j = 2; j <= tot; j++) ret.a[i][j] = (ret.a[i][j] + x.a[i][k] * y.a[k][j] % Mod) % Mod; return ret; } Matrix operator ^ (Matrix x, int y) { Matrix ret = x; y--; while (y) { if (y & 1) ret = ret * x; y >>= 1, x = x * x; } return ret; } int main() { read(n), read(m), read(T), read(s), read(t); s++, t++, tot = 1; for (int i = 1; i <= m; i++) { int x, y; read(x), read(y); a[++tot] = (Node) {++x, ++y}; a[++tot] = (Node) {y, x}; e[x].push_back(tot - 1), e[x].push_back(tot); e[y].push_back(tot - 1), e[y].push_back(tot); } Matrix tx; tx.Clear(); for (int i = 1; i <= n; i++) for (int j = 0; j < e[i].size(); j++) for (int k = 0; k < e[i].size(); k++) { int x = e[i][j], y = e[i][k]; if (x == y || (x ^ 1) == y) continue; if (a[x].y == a[y].x) tx.a[x][y] = 1; } tx = tx ^ (T - 1); int ans = 0; for (int i = 2; i <= tot; i++) for (int j = 2; j <= tot; j++) if (a[i].x == s && a[j].y == t) ans = (ans + tx.a[i][j]) % Mod; cout << ans << "\n"; return 0; }
bzoj 1875 [SDOI2009]HH去散步 矩陣乘法