列表

详情


NC51081. XOR

描述

XOR(异或)是一种二元逻辑运算,其运算结果当且仅当两个输入的布尔值不相等时才为真,否则为假。 XOR 运算的真值表如下(表示真,表示假):

而两个非负整数的是指将它们表示成二进制数,再在对应的二进制位进行运算。

譬如的计算过程如下:

QQ20180128145728.png

故 12 XOR 9 = 5。
容易验证, XOR 运算满足交换律与结合律,故计算若干个数的 XOR 时,不同的计算顺序不会对运算结果造成影响。从而,可以定义 K 个非负整数 A_KA的 XOR 和为

考虑一个边权为非负整数的无向连通图,节点编号为 1 到 N,试求出一条从 1 号节点到 N 号节点的路径,使得路径上经过的边的权值的 XOR 和最大。
路径可以重复经过某些点或边,当一条边在路径中出现了多次时,其权值在计算 XOR 和时也要被计算相应多的次数,具体见样例。


输入描述

第一行包含两个整数 N 和 M, 表示该无向图中点的数目与边的数目。
接下来 MM 行描述 MM 条边,每行三个整数 S_i,T_i,D_i,表示 S_iT_i之间存在一条权值为 D_i的无向边。
图中可能有重边或自环。

输出描述

仅包含一个整数,表示最大的XOR和(十进制结果)

示例1

输入:

5 7 
1 2 2 
1 3 2 
2 4 1 
2 5 1 
4 5 3 
5 3 4 
4 3 2 

输出:

6

说明:

QQ20180128150132.png

如图,路径1 \rightarrow 2 \rightarrow 4 \rightarrow 3 \rightarrow 5 \rightarrow 2 \rightarrow 4 \rightarrow 5对应的XOR和为
2 \ XOR \ 1 \ XOR \ 2\ XOR\ 4 \ XOR\ 1 \ XOR\ 1 \ XOR \ 3 = 6
当然,一条边数更少的路径1 \rightarrow 3 \rightarrow 5对应的XOR和也是2 XOR 4 = 6。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 125ms, 内存消耗: 9140K, 提交时间: 2019-11-07 13:25:10

#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAXN = 1e5 + 5;
struct edge
{
	int to;
	ll dis;
	int nex;
}e[MAXN * 2];
int head[MAXN], tot;
void init()
{
	memset(head, -1, sizeof(head));
	tot = 0;
}
void add(int in, int to, ll dis)
{
	e[tot] = edge{ to,dis,head[in] };
	head[in] = tot++;
}
bool vis[MAXN];
ll val[MAXN];
struct LB
{
	static const int wei = 63;
	ll b[wei + 1], cnt;//cnt是个数
	void init()
	{
		cnt = 0;
		memset(b, 0, sizeof(b));
	}
	bool insert(ll x)//插入
	{
		for (int i = wei; i >= 0; i--)
		{
			if (x & (1LL << i))
			{
				if (!b[i])
				{
					b[i] = x;
					cnt++;
					return true;
				}
				x ^= b[i];
			}
		}
		return false;
	}
	ll Max(ll x)//与x异或的最大值
	{
		ll res = x;
		for (int i = wei; i >= 0; i--)
			res = max(res, res ^ b[i]);
		return res;
	}
}lb;
int n, m;
void dfs(int u)
{
	vis[u] = true;
	for (int i = head[u]; i + 1; i = e[i].nex)
	{
		int to = e[i].to;
		if (vis[to])
			lb.insert(val[u] ^ e[i].dis ^ val[to]);
		else
		{
			val[to] = val[u] ^ e[i].dis;
			dfs(to);
		}
	}
}
int main()
{
	init();
	sc("%d%d", &n, &m);
	while (m--)
	{
		int a, b; ll c;
		sc("%d%d%lld", &a, &b, &c);
		add(a, b, c);
		add(b, a, c);
	}
	dfs(1);
	ll ans = lb.Max(val[n]);
	pr("%lld\n", ans);
}

C++11(clang++ 3.9) 解法, 执行用时: 239ms, 内存消耗: 30840K, 提交时间: 2020-03-03 10:28:42

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF=0x3f3f3f3f;
const int MOD=10000007;
const int maxn=1e6+10;
int n,m;
struct edge
{
	int to;
	LL w;
 };
vector<edge> g[maxn];
LL d[maxn];
void insert(LL x)
{
	for(int i=60;i>=0;i--)
	{
		if((x>>i)&1)
		{
			if(!d[i])
			{
				d[i]=x;
				break;
			}
			else
			x^=d[i];
		}
	}
}
LL query_max(LL x)
{
	LL ans=x;
	for(int i=60;i>=0;i--)
	ans=max(ans,ans^d[i]);
	return ans;
}
bool vis[maxn];
LL dist[maxn];
void DFS(int u)
{
	vis[u]=true;
	for(auto it:g[u])
	{
		int v=it.to;
		LL w=it.w;
		if(!vis[v])
		{
			dist[v]=dist[u]^w;
			DFS(v);
		}
		else
		insert(dist[u]^dist[v]^w);
	}
}
int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int u,v;
		LL w;
		scanf("%d %d %lld",&u,&v,&w);
		g[u].push_back(edge{v,w});
		g[v].push_back(edge{u,w});
		
	}
	DFS(1);
	printf("%lld\n",query_max(dist[n]));
	return 0;
}

上一题