bzoj2115【WC2001】Xor

2115: [Wc2011] Xor

Time Limit: 10 Sec  Memory Limit: 259 MB

Submit: 2059  Solved: 856

[Submit][Status][Discuss]

Description

Input

第一行包括两个整数N和 M, 表示该无向图中点的数目与边的数目。

接下来M 行描写叙述 M 条边,每行三个整数Si。Ti ,Di,表示 Si 与Ti之间存在 一条权值为 Di的无向边。 图中可能有重边或自环。

Output

仅包括一个整数,表示最大的XOR和(十进制结果),注意输出后加换行回车。

Sample Input

5 7

1 2 2

1 3 2

2 4 1

2 5 1

4 5 3

5 3 4

4 3 2

Sample Output

6

HINT

贪心+线性基(什么是线性基...我仅仅知道宋仲基2333)

有一个性质,一个数被异或两次就等于0。所以一条边在路径中出现偶数次就会被抵消。那么我们就能够随便找一条1到n的路径,然后把它异或一些简单环,就能够得到其它路径。

如今我们要找出无向图中的全部简单环,DFS的过程中加一些推断就能够了。

于是问题就变成从一个数组中找几个数。让他们和还有一个数的异或和最大。方法是对于这个数组求线性基。然后在线性基里倒着贪心。(详见代码)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 50005
#define maxm 200005
using namespace std;
int n,m,cnt,tot,head[maxn];
ll ans,d[maxn],a[maxm],b[100];
bool vst[maxn];
struct edge_type{int next,to;ll w;}e[maxm];
inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void add_edge(int x,int y,ll w)
{
	e[++cnt]=(edge_type){head[x],y,w};head[x]=cnt;
	e[++cnt]=(edge_type){head[y],x,w};head[y]=cnt;
}
inline void dfs(int x)
{
	vst[x]=true;
	for(int i=head[x];i;i=e[i].next)
	{
		int y=e[i].to;
		if (!vst[y])
		{
			d[y]=d[x]^e[i].w;
			dfs(y);
		}
		else a[++tot]=d[x]^d[y]^e[i].w;
	}
}
int main()
{
	n=read();m=read();
	F(i,1,m)
	{
		int x=read(),y=read();ll z=read();
		add_edge(x,y,z);
	}
	dfs(1);
	ans=d[n];
	F(i,1,tot) D(j,63,0) if ((a[i]>>j)&1)
	{
		if (!b[j]){b[j]=a[i];break;}
		else a[i]^=b[j];
	}
	D(i,63,0) if (b[i]&&((ans>>i)&1)==0) ans^=b[i];
	printf("%lld\n",ans);
	return 0;
}
时间: 2025-01-01 20:48:30

bzoj2115【WC2001】Xor的相关文章

【WC2001】【cogs358】高性能计算机(动态规划)

[WC2001][cogs358]高性能计算机(动态规划) ##题面 [问题描述] 现在有一项时间紧迫的工程计算任务要交给你--国家高性能并行计算机的主管工程师--来完成.为了尽可能充分发挥并行计算机的优势,我们的计算任务应当划分成若干个小的子任务. 这项大型计算任务包括A和B两个互不相关的较小的计算任务.为了充分发挥并行计算机的运算能力,这些任务需要进行分解.研究发现,A和B都可以各自划分成很多较小的子任务,所有的A类子任务的工作量都是一样的,所有的B类子任务也是如此(A和B类的子任务的工作量

【BZOJ2337】Xor和路径(高斯消元)

[BZOJ2337]Xor和路径(高斯消元) 题面 BZOJ 题解 我应该多学点套路: 对于xor之类的位运算,要想到每一位拆开算贡献 所以,对于每一位拆开来看 好了,既然是按位来算 我们就只需要计算从\(1\)号点开始 到\(n\)的路径中,路径的异或和为\(1\)的概率 显然没法算 还是一样的 考虑高斯消元 对于每一个节点\(i\) \[f[i]=\sum_{w(u,i)=1}\frac{1-f[u]}{op[u]}+\sum_{w(u,i)=1}\frac{f[u]}{op[u]}\] 其

【HDU3949】XOR

[题目大意] 给定一个数组,求这些数组通过异或能得到的数中的第k小是多少. 传送门:http://vjudge.net/problem/HDU-3949 [题解] 首先高斯消元求出线性基,然后将k按照二进制拆分即可. 注意当高斯消元结束后若末尾有0则第1小是0 特判一下然后k--. 然后HDU输出long long是用%I64d 无论C++还是G++都是.(虽然我用了lld也AC了) 1 #include<iostream> 2 #include<cstdio> 3 #includ

【BZOJ2115】【Wc2011】 Xor 线性基 异或最长路

#include <stdio.h> int main() { puts("转载请注明出处谢谢"); puts("http://blog.csdn.net/vmurder/article/details/43410545"); } 题意:找一条异或最长路. 题解:先随便来一条路径,然后我们发现这条路径上可以随便加简单环(不管有没有共点共边). 就是因为可以先从某点走到环上来一圈再走回来,这样来去的路径被搞没了,简直污得不行. 然后我们可以用线性基来决定去

【HNOI2011】XOR和路径

pre.cjk { font-family: "Droid Sans Fallback", monospace } p { margin-bottom: 0.25cm; line-height: 120% } a:link { } 和期望有关的题一脸懵逼QAQ 题目要求的是异或和的期望,所以就把二进制的每一位都搞一遍,最后答案就是每一位的期望和. 然后对于每一位,推出一个很鬼畜的DP方程:f[i]表示i这个点到n的概率. f[n][n]=1;然后枚举i,枚举i连的每个点,如果这条路的边

【HDU3949】XOR 线性基

#include <stdio.h> int main() { puts("转载请注明出处谢谢"); puts("http://blog.csdn.net/vmurder/article/details/43448493"); } 题意:给若干个数让你异或,然后询问第k大的异或和. 题解: 先搞出来线性基,然后第k大的异或和就是: 把k二进制拆分,第i位上有1,就把第i个线性基异或进来. 原因: 因为线性基是一堆高位上的1(或许有一些位动不了),然后把这

【Hdu4825】Xor Sum(01字典树)

Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起M次询问,每次询问中包含一个正整数 S ,之后 Zeus 需要在集合当中找出一个正整数 K ,使得 K 与 S 的异或结果最大.Prometheus 为了让 Zeus 看到人类的伟大,随即同意 Zeus 可以向人类求助.你能证明人类的智慧么? Solution 01字典树入门题 Code #include

【BZOJ】2337: [HNOI2011]XOR和路径

[算法]期望+高斯消元 [题解]因为异或不能和期望同时运算,所以必须转为加乘 考虑拆位,那么对于边权为1取反,边权为0不变. E(x)表示从x出发到n的路径xor期望. 对于点x,有E(x)=Σ(1-E(y))(边权1)||E(y)(边权0)/t[x]  t[x]为x的度. 那么有n个方程,整体乘上t[x]确保精度,右项E(x)移到左边--方程可以各种变形. 每次计算完后*(1<<k)就是贡献. 逆推的原因在于n不能重复经过,而1能重复经过,所以如果计算"来源"不能计算n,

【Math】GCD XOR 证明

题目:Given an integer N, and how many pairs (A;B) are there such that: gcd(A;B) = A xor B where 1<=B<=A<=N. 首先先爆一发,妥妥超时.其实真相是我想打表找规律.结果没什么规律可循. 后来分析:要想让GCD(A,B)==(A^B),A和B一定是同样的位数(二进制).因此打表方法可变为:(亦超时) void init() { int K=0; int last=0; for(int i=1;