www.lydsy.com/JudgeOnline/problem.php?id=2115 (题目链接)

题意

  给出一张图,可能有重边和自环,在图中找出一条从1~n的路径,使得经过的路径的权值的异或和最大,每条边可以重复经过并且重复计算异或和。

Solution

  刚看到这道题,想了10分钟完全没有思路,于是就膜了题解。

  我们先把图看成一棵树,那么我们所需要找出的路径可以分成一些环和一条从1~n的树上路径,至于树是怎么构造的以及那条从1~n的路径是怎么走的并不重要,因为我们可以通过在总路径上补环来增大异或和。于是这个问题就转化为了如何在环的异或和中选出一些使得这些值异或上从1~n的路径的异或和最大。

  于是我们先dfs一遍把环以及它的异或和抠出来,当然这些环可能并不完全,但它们可以通过互相异或来异或出没有得到的环。如果发现当前节点x的目标节点e[i].to已经被走过了,那么这个环的异或和就是${dis[x]~XOR~dis[e[i].to]~XOR~e[i].w}$。

  怎么求最大异或和呢?这需要用到一个很神的东西:线性基

  什么是线性基:

  若干数的线性基是一组数a1,a2,…an,其中ax的最高位的1在第x位。通过线性基中元素xor出的数的值域与原来的数xor出数的值域相同。 
  线性基主要有2个优秀的性质: 
  可以O(k)(二进制的位数)的求出能异或出的最大值,或者是判断一个数能否被异或出来。

  线性基的构造:

  线性基的构造有两种: 
  第一是高斯消元。通过高斯消元将二进制矩阵消成上三角矩阵或者是对角矩阵,当然消成后者时间复杂度略高,但也更为方便,求解异或和最大时一路for下去就可以了。而上三角矩阵需要判断如果答案异或上这个值能否使答案增大。 
  第二种就是一种拟阵贪心,详情参见jump大爷的博客——www.cnblogs.com/ljh2000-jump/p/5869991.html,因为证明太高深,这里也就不再赘述。

  所以这道题就很好做了对吧,这里我选择消成对角矩阵,性质就更加显然一些。

代码

// bzoj2115
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf 2147483640
#define Pi 3.1415926535898
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxn=50010,maxm=100010;
struct edge {int to,next;LL w;}e[maxm<<1];
LL dis[maxn],c[maxm<<2],bin[65];
int vis[maxn],n,m,tot,sum,cnt,head[maxn]; void link(int u,int v,LL w) {
e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;e[cnt].w=w;
e[++cnt].to=u;e[cnt].next=head[v];head[v]=cnt;e[cnt].w=w;
}
void dfs(int x) {
vis[x]=1;
for (int i=head[x];i;i=e[i].next) {
if (!vis[e[i].to]) {
dis[e[i].to]=dis[x]^e[i].w;
dfs(e[i].to);
}
else c[++sum]=dis[x]^dis[e[i].to]^e[i].w;
}
}
void Gauss() {
for (LL i=bin[60];i;i>>=1) {
int j=tot+1;
while (j<=sum && !(c[j]&i)) j++;
if (j==sum+1) continue;
swap(c[++tot],c[j]);
for (j=1;j<=sum;j++) if (j!=tot && c[j]&i) c[j]^=c[tot];
//for (int k=j+1;k<=sum;k++) if (c[k]&i) c[k]^=c[tot];
}
}
int main() {
bin[0]=1;for (int i=1;i<=60;i++) bin[i]=bin[i-1]<<1;
scanf("%d%d",&n,&m);
for (int u,v,i=1;i<=m;i++) {
LL w;
scanf("%d%d%lld",&u,&v,&w);
link(u,v,w);
}
dfs(1);
Gauss();
LL ans=dis[n];
for (int i=1;i<=tot;i++) ans=max(ans,ans^c[i]);
printf("%lld\n",ans);
return 0;
}

  

【bzoj2115】 Xor的更多相关文章

  1. 【BZOJ2115】Xor(线性基)

    [BZOJ2115]Xor(线性基) 题面 BZOJ Description Input 第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目. 接下来M 行描述 M 条边,每行三个整数Si ...

  2. 【BZOJ-2115】Xor 线性基 + DFS

    2115: [Wc2011] Xor Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 2142  Solved: 893[Submit][Status] ...

  3. 【BZOJ2115】[Wc2011] Xor 高斯消元求线性基+DFS

    [BZOJ2115][Wc2011] Xor Description Input 第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目. 接下来M 行描述 M 条边,每行三个整数Si,Ti ...

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

    [BZOJ2337]Xor和路径(高斯消元) 题面 BZOJ 题解 我应该多学点套路: 对于xor之类的位运算,要想到每一位拆开算贡献 所以,对于每一位拆开来看 好了,既然是按位来算 我们就只需要计算 ...

  5. 【bzoj2115】[Wc2011] Xor

    2115: [Wc2011] Xor Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 2512  Solved: 1049[Submit][Status ...

  6. 【HDU3949】XOR

    [题目大意] 给定一个数组,求这些数组通过异或能得到的数中的第k小是多少. 传送门:http://vjudge.net/problem/HDU-3949 [题解] 首先高斯消元求出线性基,然后将k按照 ...

  7. 【bzoj2115】【wc2011】Xor

    2115: [Wc2011] Xor Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 5380  Solved: 2249[Submit][Status ...

  8. bzoj2115【WC2001】Xor

    2115: [Wc2011] Xor Time Limit: 10 Sec  Memory Limit: 259 MB Submit: 2059  Solved: 856 [Submit][Statu ...

  9. 【bzoj2115】[Wc2011] Xor DFS树+高斯消元求线性基

    题目描述 输入 第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目. 接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si 与Ti之间存在 一条权值为 Di的无向边. 图 ...

随机推荐

  1. AC日记——codevs 1688 求逆序对

    1688 求逆序对  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描述 Description 给定一个序列a1,a2,…, ...

  2. FlashInspector 【Firefox浏览器插件,flash分析工具】

    Inspect flash(swf)'s DisplayObject with mouse. Overview the swf's DisplayObject list. Set the inspec ...

  3. 【转载】Jmeter获取响应结果中参数出现的次数

    在测试中,有时候会遇到要统计响应结果中某个参数出现了多少次,如果量级很大,一个一个数不太现实,下面讲一下实现自动打印出该参数出现的次数的方法. 例如我的响应信息为:{"ip":&q ...

  4. Android中的三种XML解析方式

    在Android中提供了三种解析XML的方式:SAX(Simple API XML),DOM(Document Objrect Model),以及Android推荐的Pull解析方式.下面就对三种解析 ...

  5. java12-6 冒泡排序法和选择排序法

    1.冒泡排序法 相邻元素两两比较,大的往后放,第一次完毕,最大值出现在了最大索引处 分析: 第一次比较排序的结果:会把其中最大的数据排到最大的索引处 第二次比较排序后的结果:因为第一次已经把最大的一个 ...

  6. 使用EditText+ListView并结合TextWatcher实现输入关键字筛选数据

    想必大家应该遇到过这样的情况,当点击Spinner控件后弹出的列表内容超多,一个一个滑动着去寻找所要的项很麻烦,尤其是当自己知道想要选择的内容,这时候如果我们只需要输入某些关键字,就可以讲上百条数据筛 ...

  7. Android_firstClass

    一个Project 创建后,大概的文件目录如下:在Android Studio每个Project,相当于Eclipse 的WorkSpace:每个Module(上图的app 目录)相当于Eclipse ...

  8. 使用Spring.net中对Ado.net的抽象封装来访问数据库

    使用Spring.net中对Ado.net的抽象封装来访问数据库     Spring.NET是一个应用程序框架,其目的是协助开发人员创建企业级的.NET应用程序.它提供了很多方面的功能,比如依赖注入 ...

  9. Android开发探秘之三:利用jsoup解析HTML页面

    这节主要是讲解jsoup解析HTML页面.由于在android开发过程中,不可避免的涉及到web页面的抓取,解析,展示等等,所以,在这里我主要展示下利用jsoup jar包来抓取cnbeta.com网 ...

  10. linux实践——简单程序破解

    一.运行login可执行程序,屏幕显示需要输入密码,随便输入一串字符,结果是Drop dead! 二.objdump -d login,对login进行反汇编,找到main函数,找到含有scanf的那 ...