[线性基] Luogu P4151 最大XOR和路径
题目描述
XOR(异或)是一种二元逻辑运算,其运算结果当且仅当两个输入的布尔值不相等时才为真,否则为假。 XOR 运算的真值表如下(11 表示真, 00 表示假):
而两个非负整数的 XOR 是指将它们表示成二进制数,再在对应的二进制位进行 XOR 运算。
譬如 1212 XOR 99 的计算过程如下:
故 1212 XOR 9 = 59=5。
容易验证, XOR 运算满足交换律与结合律,故计算若干个数的 XOR 时,不同的计算顺序不会对运算结果造成影响。从而,可以定义 KK 个非负整数 A_1A1,A_2A2,……,A_{K-1}AK−1,A_KAK的 XOR 和为
A_1A1 XOR A_2A2 XOR …… XOR A_{K-1}AK−1 XOR A_KAK
考虑一个边权为非负整数的无向连通图,节点编号为 11 到 NN,试求出一条从 11 号节点到 NN 号节点的路径,使得路径上经过的边的权值的 XOR 和最大。
路径可以重复经过某些点或边,当一条边在路径中出现了多次时,其权值在计算 XOR 和时也要被计算相应多的次数,具体见样例。
输入输出格式
输入格式:
输入文件 xor.in 的第一行包含两个整数 NN 和 MM, 表示该无向图中点的数目与边的数目。
接下来 MM 行描述 MM 条边,每行三个整数 S_iSi, T_iTi , D_iDi, 表示 S_iSi 与 T_iTi 之间存在一条权值为 D_iDi 的无向边。
图中可能有重边或自环。
输出格式:
输出文件 xor.out 仅包含一个整数,表示最大的 XOR 和(十进制结果)。
输入输出样例
说明
【样例说明】
如图,路径1 \rightarrow 2 \rightarrow 4 \rightarrow 3 \rightarrow 5 \rightarrow 2 \rightarrow 4 \rightarrow 51→2→4→3→5→2→4→5对应的XOR和为
22 XOR 11 XOR 22 XOR 44 XOR 11 XOR 11 XOR 3 = 63=6
当然,一条边数更少的路径1 \rightarrow 3 \rightarrow 51→3→5对应的XOR和也是22 XOR 4 = 64=6。
【数据规模】
对于 20 \%20% 的数据,N \leq 100N≤100, M \leq 1000M≤1000,D_i \leq 10^{4}Di≤104;
对于 50 \%50% 的数据,N \leq 1000N≤1000, M \leq 10000M≤10000,D_i \leq 10^{18}Di≤1018;
对于 70 \%70% 的数据,N \leq 5000N≤5000, M \leq 50000M≤50000,D_i \leq 10^{18}Di≤1018;
对于 100 \%100% 的数据,N \leq 50000N≤50000, M \leq 100000M≤100000,D_i \leq 10^{18}Di≤1018。
题解
- 任意一条1到n的路径的异或和,都可以由任意一条1到n路径的异或和与图中的一些环的异或和来组合得到
- 在这种条件下,我们可以考虑把环储存为一个线性基的元素
- 如果有多条1到n的路径,那么这显然也构成一个环,也是可以抵消异或的任意一条其他的路径
- 然后就好做了
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #define ll long long 5 using namespace std; 6 const ll N=110,M=50010; 7 ll n,m,cnt,vis[M],head[M*2],dis[M],mi[N],b[N]; 8 struct edge{ ll from,to,v; }e[M*4]; 9 void insert(ll x,ll y,ll v) 10 { 11 e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt,e[cnt].v=v; 12 e[++cnt].to=x,e[cnt].from=head[y],head[y]=cnt,e[cnt].v=v; 13 } 14 void update(ll x) { for (ll i=60;i>=0;i--) if (mi[i]&x) { if (b[i]) x^=b[i]; else { b[i]=x; break; } } } 15 void dfs(ll x) 16 { 17 vis[x]=1; 18 for (ll i=head[x];i;i=e[i].from) if (vis[e[i].to]) update(dis[e[i].to]^e[i].v^dis[x]); else dis[e[i].to]=dis[x]^e[i].v,dfs(e[i].to); 19 } 20 ll query(ll x) 21 { 22 ll ans=x; 23 for (ll i=60;i>=0;i--) ans=max(ans,ans^b[i]); 24 return ans; 25 } 26 int main() 27 { 28 scanf("%lld%lld",&n,&m); 29 mi[0]=1; for (ll i=1;i<=60;i++) mi[i]=mi[i-1]*2; 30 for (ll i=1,x,y,z;i<=m;i++) scanf("%lld%lld%lld",&x,&y,&z),insert(x,y,z); 31 dfs(1),printf("%lld",query(dis[n])); 32 }