洛谷 P6569 [NOI Online #3 提高组] 魔法值 题解
魔法值
Description
给定一张有 \(n\) 个点和 \(m\) 条边的无向图。在时刻 \(j\) 时,\(i\) 号节点的权值为 \(f_{i,j}\)。
已知 \(\forall i \in [1,n],\ f_{i,0}\) 的值。对于每个新的时刻 \(j\),\(f\) 满足如下变换:
\[f_{u,j} = \bigoplus_{v} f_{v,j-1}
\]
其中 \(v\) 为与 \(u\) 直接相连的节点。
给定 \(q\) 次询问,对于第 \(i\) 次询问,需要回答时刻 \(a_i\) 时,\(1\) 号节点的权值是多少。
对于 \(100\%\) 的数据,满足 \(1 \leq n,q \leq 100\),\(1 \leq m \leq \frac{n(n-1)}{2}\),\(1\leq a_i < 2^{32}\),\(0\leq f_{i,0} < 2^{32}\)。
Solution
注意到图并没有什么用,有用的只是点与点间的直接连通性。
设 \(e_{i,j}\) 表示 \(i\) 与 \(j\) 是否有直接连边,则有
\[f_{u,j} = \bigoplus_{v = 1}^{n} f_{v,j - 1} \times e_{i,j}
\]
不妨把 \(f_{u,j}\) 抽象为一维矩阵 \(F_i\),并设邻接矩阵为 \(E\),那么则有
\[F_i = F_{i-1} \star E
\]
其中,\(\star\) 为 \((\times,\oplus)\) 运算。
容易发现,如果 \(\star\) 运算满足结合律,那么必有
\[F_i = F_0 \star E^i
\]
其中幂运算是在 \(\star\) 意义下的。
对 \(\star\) 满足结合律的证明:
\[\begin{aligned} ((A \star B) \star C)_{ij} &= \bigoplus_{k} \left( (A \star B)_{ik} \times C_{kj} \right) \\ &= \bigoplus_{k} \left( \left( \bigoplus_{l} (A_{il} \times B_{lk}) \right) \times C_{kj} \right) \\ &= \bigoplus_{k} \bigoplus_{l} \left( (A_{il} \times B_{lk}) \times C_{kj} \right) \\ &= \bigoplus_{l} \bigoplus_{k} \left( A_{il} \times (B_{lk} \times C_{kj}) \right) \\ &= \bigoplus_{l} \left( A_{il} \times \left( \bigoplus_{k} (B_{lk} \times C_{kj}) \right) \right) \\ &= \bigoplus_{l} \left( A_{il} \times (B \star C)_{lj} \right) = (A \star (B \star C))_{ij}. \end{aligned} \]
对于每一次询问,处理出 \(E\) 的正整数次幂即可。每次都处理显然过于麻烦,因此考虑倍增:对于每一个 \(j\),预处理出矩阵 \(E\) 的 \(2^j\) 次幂。累计答案时拆位即可。
Code
#include <bits/stdc++.h>
#define int long long
#define inf 1e18
#define debug cout << '!';
#define filein(x) freopen(#x".in", "r", stdin);
#define fileout(x) freopen(#x".out", "w", stdout);
#define file(x) filein(x) fileout(x)
// #define Fast_IO
using namespace std;
#ifdef Fast_IO
inline int read() {
int x = 0, f = 1; char c = getchar();
while (c < '0' or c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0' and c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
void write(int x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) write(x / 10);
putchar(x % 10 + '0'); return;
}
#endif
const int MaxN = 105, MaxM = 40;
int n, m, q;
struct Mat {
int row, col;
int mt[MaxN][MaxN];
Mat() { memset(mt, 0, sizeof(mt)); }
friend Mat operator * (Mat x, Mat y) {
Mat res;
res.row = x.row, res.col = y.col;
for (int k = 1; k <= x.col; k++) {
for (int j = 1; j <= y.col; j++) {
for (int i = 1; i <= x.row; i++) {
res.mt[i][j] ^= x.mt[i][k] * y.mt[k][j];
}
}
}
return res;
}
} I, E[MaxM];
int f[MaxN];
Mat qpow(Mat x, int p) {
if (p == 0) return I;
if (p == 1) return x;
Mat tmp = qpow(x * x, p / 2);
if (p & 1) return tmp * x;
return tmp;
}
signed main() {
cin.tie(0) -> sync_with_stdio(0);
cin >> n >> m >> q;
for (int i = 1; i <= n; i++) {
cin >> f[i];
}
E[0].row = E[0].col = n;
for (int i = 1; i <= m; i++) {
int u, v; cin >> u >> v;
E[0].mt[u][v] = E[0].mt[v][u] = 1;
}
for (int i = 1; i < 32; i++) {
E[i] = E[i - 1] * E[i - 1];
}
for (; q--; ) {
int x; cin >> x;
Mat ans;
for (int i = 1; i <= n; i++) {
ans.mt[1][i] = f[i];
}
ans.row = 1, ans.col = n;
for (int i = 0; i < 32; i++) {
if ((x >> i) & 1) ans = ans * E[i];
}
cout << ans.mt[1][1] << '\n';
}
return 0;
}

浙公网安备 33010602011771号