题目大意:给你一张$n$个点$m$条边的无向图,求一条$1->n$的路径,使得经过路径值的异或值最大(重复经过重复计算)
题解:某条路$k$被重复走了两次,那么它的权值对答案的贡献就是$0$,但是通过这条路径$k$,可以到达它连接的另一个点。
可以将路径拆成两部分,一部分是环,另一部分是链。假设我们选择了一条从$1->n$的链,然后可以选择一些环来增广这条链。可以枚举所有环,将环上异或和扔进线性基,然后用任意一条$1->n$的链作为初值,求线性基与这条链的最大异或和。
卡点:无
C++ Code:
#include <cstdio> #define maxn 50010 #define maxm 100010 int head[maxn], cnt; struct Edge { int to, nxt; long long w; } e[maxm << 1]; void addE(int a, int b, long long c) { e[++cnt] = (Edge) {b, head[a], c}; head[a] = cnt; } long long p[64]; inline void add(long long x) { for (int i = 62; ~i; i--) if (x & 1ll << i) { if (p[i]) x ^= p[i]; else {p[i] = x; break;} } } inline long long ask(long long x) { long long ans = x; for (int i = 62; ~i; i--) if (ans < (ans ^ p[i])) ans = ans ^ p[i]; return ans; } long long d[maxn]; bool vis[maxn]; void dfs(int rt, long long now) { d[rt] = now; vis[rt] = true; for (int i = head[rt]; i; i = e[i].nxt) { int v = e[i].to; if (!vis[v]) dfs(v, d[rt] ^ e[i].w); else add(d[rt] ^ d[v] ^ e[i].w); } } int n, m; int main() { scanf("%d%d", &n, &m); for (int i = 0; i < m; i++) { int a, b; long long c; scanf("%d%d%lld", &a, &b, &c); addE(a, b, c); addE(b, a, c); } dfs(1, 0); printf("%lld ", ask(d[n])); return 0; }