「WC2011」最大XOR和路径 题解
题目链接
思路
首先看到题面,“最大”“异或”,联想到了什么?
没错,线性基。
不会的同学请先学习:线性基。
但是这道题,因为是在图里,所以不能直接简单地用线性基求解。
观察题目中的图,我们可以发现(吗?),答案一定是由从 $1$ 到 $N$ 的一条路径上的异或和以及若干环上的异或和构成的。
首先我们要理清一个问题:从 $1$ 到 $N$ 的路径不用特意去选,它对答案没有任何影响。
   借用大佬的博客 来解释:称从 $1$ 到 $N$ 的路径为“主要路”。
   可以发现,所有的“主要路”两两之间会构成一个环。
如果一条“主要路” $A$ 优于 $B$,而我们选择了 $B$。
但 $A$ 和 $B$ 也会构成一条环加入线性基,如果更优,肯定会在求解环节被异或上。
这样一来,就相当于沿 $A$ 跑了一遍。
回到原来的问题,那么我们要选择哪些环使得异或和最大呢?
这个时候,我们就会发现,又绕回了最基本的最大异或和问题。
那么我们就可以把路径上的每个环上的异或和放入线性基,最后用我们“主要路”的路径和为基数,去求解最大异或和。
就是这样啦(*^▽^*)
那么,上代码!
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 50005; const int maxm = 100005; typedef unsigned long long ull; struct edge { int to,next; ull dis; edge() { to = next = dis = 0; } edge(int to,int next,ull dis):to(to),next(next),dis(dis){} }Edge[maxm << 1]; int head[maxn],cnt; void add(int u,int v,ull t) { Edge[++ cnt] = edge(v , head[u] , t); head[u] = cnt; return ; } ull d[70]; void insert(ull x) { for(int i = 63;i >= 0;-- i) { if((x >> i) & 1) { if(d[i])x ^= d[i]; else { d[i] = x; break ; } } } return ; } int n,m; ull sum[maxn]; bool vis[maxn]; void dfs(int x,ull ans) { vis[x] = true; sum[x] = ans; for(int i = head[x];i;i = Edge[i].next) { int v = Edge[i].to; ull w = Edge[i].dis; if(!vis[v]) { dfs(v , ans ^ w); } else {//环 insert(ans ^ w ^ sum[v]);//这里是环上的异或和 //画个图,思考一下,为什么环上异或和是这样 } } return ; } ull query(ull x) { for(int i = 63;i >= 0;-- i) { if((x ^ d[i]) > x)x ^= d[i]; } return x; } int main() { scanf("%d%d",&n,&m); for(int i = 1;i <= m;++ i) { int u,v; ull t; scanf("%d%d%llu",&u,&v,&t); add(u , v , t); add(v , u , t); } dfs(1 , 0); printf("%llu",query(sum[n])); return 0; }
 完结撒花✿✿ヽ(°▽°)ノ✿
                    
                
                
            
        
浙公网安备 33010602011771号