最大XOR和路径
格式难调,题面就不放了。
分析:
一道需要深刻理解线性基的题目。
好久没打过线性基的题了,一开始看到这题还是有点蒙逼的,想了几种方法全被否定了。还是看了大佬的题解才会做的。
首先我们能想到,在图中从$1$走到$n$有这么两种情况,一种是一条链直接走到$n$,另一种是先走链然后绕若干个环然后回到链上走到$n$。对于这道题显然我们是要考虑所有的环的(由异或的性质可知)。
然后我们又可以发现,如果一条链和一个环中间有一条路径相连,那么我们从链上走到环上时会经过这条路径一次,从环上回到链上时又会走这条路径一次,那么两次走过的路径异或和就是$0$!
再看,如果从$1$走到$n$有若干条链,那么这些链会相互构成若干个环,如果我们走了一条链,然后让这条链异或这些环,就可以得到对应的另一条链!(可以自己画图分析一下,博主太懒不想画图_(:з」∠)_)
综合一下上面的性质,我们就能得到一种算法:进行一遍$DFS$,把所有的环构造成线性基,然后把任意一条从$1$到$n$的链放入线性基中求最大异或和。
$SO$,这道黑题就这么过了。
博主手残写了个$namespace$,不过好像跑得还挺快。
Code:
//It is made by HolseLee on 3rd Sep 2018 //Luogu.org P4151 #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<iostream> #include<iomanip> #include<algorithm> using namespace std; typedef long long ll; const int N=5e4+7,M=2e5+7;; int n,m,head[N],cnte; ll dis[N],b[70]; bool vis[N]; struct Node { int to,nxt; ll val; Node() {} Node(int _to,ll _val,int _nxt): to(_to),val(_val),nxt(_nxt) {} }e[M]; namespace LinerBase { void insert(ll x) { for(int i=63; i>=0; --i) { if( !(x>>i) ) continue; if( !b[i] ) { b[i]=x; break; } else { x^=b[i]; } } } ll quary(ll x) { ll ret=x; for(int i=63; i>=0; --i) { if( (ret^b[i])>ret ) ret^=b[i]; } return ret; } } inline ll read() { char ch=getchar(); ll num=0; bool flag=false; while( ch<'0' || ch>'9' ) { if( ch=='-' ) flag=true; ch=getchar(); } while( ch>='0' && ch<='9' ) { num=num*10+ch-'0'; ch=getchar(); } return flag ? -num : num; } inline void add(int x,int y,ll z) { e[++cnte]=Node(y,z,head[x]); head[x]=cnte; } void dfs(int x,ll now) { dis[x]=now, vis[x]=true; for(int i=head[x]; i; i=e[i].nxt) { if(!vis[e[i].to]) dfs(e[i].to,now^e[i].val); else LinerBase::insert(now^e[i].val^dis[e[i].to]); } } int main() { n=read(); m=read(); int x,y;ll z; for(int i=1; i<=m; ++i) { x=read(), y=read(), z=read(); add(x,y,z); add(y,x,z); } dfs(1,0); printf("%lld ",LinerBase::quary(dis[n])); return 0; }