BZOJ2115 WC2011 Xor DFS+高斯消元
题意:给定一张无向图,求1到N异或和最大的路径,允许重复经过。
题解:首先跑出1到N的一条路径,答案就是在这条路径上不断加环。首先用DFS处理出所有基环的异或和(其他环一定由基环构成,重复部分异或之后就会消掉),然后就是从一堆数里选任意个数使得异或和最小了,怎么做可以去看莫涛的课件(同解01异或方程),这里我简单介绍一下。
通过高斯消元,我们对原来的数进行操作,使得所有原来的数都可以用操作之后的数来组合而成(这玩意貌似叫线性基啊)。具体做法就是从高到低暴力枚举每一位i,找到一个第i位为1的数j,然后将所有除这个数外第i位为1的数x^=j,最后消出来的b就是线性基了。直观看起来很显然,具体的证明我也不会QAQ。
然后可以暴力枚举,看某个环是不是要加进去了。
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define ll long long const int MAXN=50000+2; const int MAXM=100000+2; struct HASH{ int u; ll w; HASH *next; HASH(){} HASH(int _u,ll _w,HASH *_next):u(_u),w(_w),next(_next){} }*table[MAXN],mem[MAXM]; int N,M,C,cnt; ll ans,d[MAXN],w[2*MAXM]; bool flag[MAXN]; void Insert(int u,int v,ll w){ table[u]=&(mem[cnt++]=HASH(v,w,table[u]));} void DFS(int x){ flag[x]=1; for(HASH *p=table[x];p;p=p->next) if(!flag[p->u]) d[p->u]=d[x]^p->w,DFS(p->u); else cnt++,w[cnt]=d[x]^d[p->u]^p->w; } void Gauss(){ ll i=1; for(int j=60;j;j--) i<<=1; for(;i;i>>=1){ int j=C+1; while(j<=cnt && !(w[j]&i)) j++; if(j>cnt) continue; C++; swap(w[C],w[j]); for(int k=1;k<=cnt;k++) if(k!=C && (w[k]&i)) w[k]^=w[C]; } } int main(){ cin >> N >> M; for(int i=1;i<=M;i++){ int a,b;ll c; scanf("%d %d %lld",&a,&b,&c); Insert(a,b,c),Insert(b,a,c); } cnt=0,DFS(1); Gauss(),ans=d[N]; for(int i=1;i<=C;i++) ans=max(ans,ans^w[i]); cout << ans << endl; return 0; }