BZOJ 2115: [Wc2011] Xor 线性基
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2115
解法:
膜:http://www.cnblogs.com/ljh2000-jump/p/5869925.html
这道题要求从1到n的最大xor和路径,存在重边,允许经过重复点、重复边。那么在图上作图尝试之后就会发现,路径一定是由许多的环和一条从1到n的路径组成。容易发现,来回走是没有任何意义的,因为来回走意味着抵消。考虑这道题求得是路径xor和最大,所以必然我们要想办法处理环的情况。我的做法是任意地先找出一条从1到n的路径,把这条路径上的xor和作为ans初值(先不管为什么可行),然后我们的任务就变成了求若干个环与这个ans初值所能组合成的xor最大值。显然,我们需要预处理出图上所有的环,并处理出所有环的环上xor值,这当然是dfs寻找,到n的路径的时候顺便求一下就可以了。
当我们得到了若干个环的xor值之后,因为是要求xor最大值,我们就可以构出这所有xor值的线性基。构出之后,再用ans在线性基上取max就可以了。
为什么可以这么做? 证明在上面大牛博客里有证明。
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 50010; const int maxm = 200010; int n, m, edgecnt; int head[maxn]; bool vis[maxn]; LL dx[maxn]; LL p[70]; LL circle[maxm], ans; void init(){ memset(head, -1, sizeof(head)); edgecnt = 0; } struct edge{ int to,next; LL w; edge(){} edge(int to, int next, LL w):to(to),next(next),w(w){} }E[maxm]; int cnt = 0; void add(int u, int v, LL w){ E[edgecnt].to = v, E[edgecnt].next = head[u], E[edgecnt].w = w, head[u] = edgecnt++; } void dfsloop(int x){ vis[x] = 1; for(int i=head[x]; i+1; i=E[i].next){ int to = E[i].to; if(!vis[to]) dx[to] = dx[x]^E[i].w, dfsloop(to); else{ circle[++cnt] = dx[to]^dx[x]^E[i].w; } } } int main() { int x,y; LL z; init(); scanf("%d %d", &n,&m); for(int i=1; i<=m; i++){ scanf("%d %d %lld", &x,&y,&z); add(x, y, z); add(y, x, z); } dfsloop(1); ans = dx[n];//任取一条从1到n的路径,并得到其xor和 for(int i=1; i<=cnt; i++){ for(int j=62; j>=0; j--){ if(!(circle[i]>>j)) continue; if(!p[j]){ p[j] = circle[i]; break; } circle[i] ^= p[j]; } } //for(int i=62;i>=0;i--) if(!(ans>>i)) ans^=p[i]; //ans有初值,不能直接根据这一位是否为0来判断是否更大,max更为稳妥 for(int i=62; i>=0; i--){ if((ans^p[i])>ans){ ans = ans^p[i]; } } printf("%lld\n", ans); return 0; }