bzoj 2115 Xor - 线性基 - 贪心

题目传送门

  这是个通往vjudge的虫洞

  这是个通往bzoj的虫洞

题目大意

  问点$1$到点$n$的最大异或路径。

  因为重复走一条边后,它的贡献会被消去。所以这条路径中有贡献的边可以看成是一条$1$到$n$的简单路径加上若干个环。

  因此可以找任意一条路径,然后找出所有环扔进线性基跑出最大异或和。

  但是找出所有环可能会T掉,但是仔细画图发现,并不需要找出所有环,例如:

  在上图中,你并不需找出所有的环,只用找出1 - 3 - 4 - 2和3 - 5 - 6 - 4这两个环,它们异或后就能得到环1 - 3 - 5 - 6 - 4 - 2。

  至于找这个环,可以用dfs生成树来找。当出现返祖边的时候就意味着找到了一个环。

  然后可以记一个异或的前缀和,这样就可以$O(1)$算出环上的边权的异或和。

  对于任意一条路径得到的异或和如果为$s$,那么我们只需要考虑线性基的每一位上,如果异或上它,能够使答案变大,就异或上它。

  因为线性基不能保证最大的异或和由之前扔进去的所有数得到,所以必须这么贪一下心。

  这样的正确性显然。

Code

  1 /**
  2  * bzoj
  3  * Problem#2115
  4  * Accepted
  5  * Time: 740ms
  6  * Memory: 7040k
  7  */
  8 #include <bits/stdc++.h>
  9 #ifndef WIN32
 10 #define Auto "%lld"
 11 #else
 12 #define Auto "%I64d"
 13 #endif
 14
 15 using namespace std;
 16 typedef bool boolean;
 17
 18 #define ll long long
 19
 20 typedef class LinearBasis {
 21     public:
 22         ll b[64];
 23
 24         LinearBasis() {    }
 25
 26         void insert(ll x) {
 27             for (int i = 62; ~i; i--) {
 28                 if (x & (1ll << i))    x ^= b[i];
 29                 if (x & (1ll << i)) {
 30                     b[i] = x;
 31                     for (int j = i - 1; ~j; j--)
 32                         if (b[i] & (1ll << j))
 33                             b[i] ^= b[j];
 34                     for (int j = i + 1; j <= 62; j++)
 35                         if (b[j] & (1ll << i))
 36                             b[j] ^= b[i];
 37                     break;
 38                 }
 39             }
 40         }
 41
 42         ll getAns(ll ans) {
 43             for (int i = 0; i <= 62; i++)
 44                 if ((ans ^ b[i]) > ans)
 45                         ans ^= b[i];
 46             return ans;
 47         }
 48 }LinearBasis;
 49
 50 typedef class Edge {
 51     public:
 52         int end, next;
 53         ll w;
 54
 55         Edge(int end = 0, int next = 0, ll w = 0):end(end), next(next), w(w){    }
 56 }Edge;
 57
 58 typedef class MapManager {
 59     public:
 60         int ce;
 61         int *h;
 62         Edge* es;
 63
 64         MapManager() {    }
 65         MapManager(int n, int m):ce(0) {
 66             h = new int[(n + 1)];
 67             es = new Edge[(m + 1)];
 68             memset(h, 0, sizeof(int) * (n + 1));
 69         }
 70
 71         void addEdge(int u, int v, ll w) {
 72             es[++ce] = Edge(v, h[u], w);
 73             h[u] = ce;
 74         }
 75
 76         Edge& operator [] (int p) {
 77             return es[p];
 78         }
 79 }MapManager;
 80
 81 int n, m;
 82 ll *xs;
 83 MapManager g;
 84 LinearBasis lb;
 85 boolean *vis;
 86
 87 inline void init() {
 88     scanf("%d%d", &n, &m);
 89     xs = new ll[(n + 1)];
 90     g = MapManager(n, m << 1);
 91     vis = new boolean[(n + 1)];
 92     ll w;
 93     for (int i = 1, u, v; i <= m; i++) {
 94         scanf("%d%d"Auto, &u, &v, &w);
 95         g.addEdge(u, v, w);
 96         g.addEdge(v, u, w);
 97     }
 98 }
 99
100 void dfs(int p) {
101     vis[p] = true;
102     for (int i = g.h[p]; i; i = g[i].next) {
103         int e = g[i].end;
104         if (vis[e])
105             lb.insert(xs[e] ^ xs[p] ^ g[i].w);
106         else {
107             xs[e] = xs[p] ^ g[i].w;
108             dfs(e);
109         }
110     }
111 }
112
113 inline void solve() {
114     memset(vis, false, sizeof(boolean) * (n + 1));
115     xs[1] = 0;
116     dfs(1);
117     printf(Auto"\n", lb.getAns(xs[n]));
118 }
119
120 int main() {
121     init();
122     solve();
123     return 0;
124 }

原文地址:https://www.cnblogs.com/yyf0309/p/8502874.html

时间: 2024-11-18 23:19:39

bzoj 2115 Xor - 线性基 - 贪心的相关文章

BZOJ 2115: [Wc2011] Xor 线性基

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2115 解法: 膜:http://www.cnblogs.com/ljh2000-jump/p/5869925.html 这道题要求从1到n的最大xor和路径,存在重边,允许经过重复点.重复边.那么在图上作图尝试之后就会发现,路径一定是由许多的环和一条从1到n的路径组成.容易发现,来回走是没有任何意义的,因为来回走意味着抵消.考虑这道题求得是路径xor和最大,所以必然我们要想办法处理环的情

BZOJ 2115 [Wc2011] Xor ——线性基

[题目分析] 显然,一个路径走过两边是不需要计算的,所以我么找到一条1-n的路径,然后向该异或值不断异或简单环即可. 但是找出所有简单环是相当复杂的,我们只需要dfs一遍,找出所有的环路即可,因为所有的简单环都可以经过各种各样的异或得到. 然后线性基,在从高位向低位贪心即可,至于证明,需要拟阵的相关知识. [代码] #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath>

Xor HYSBZ - 2115 (线性基)

Xor HYSBZ - 2115 题意:给一个树,求1到n的最长路径.这里的路径定义为异或和. 线性基~~ 1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 struct LiBase{ 5 ll a[63]; 6 //初始化 7 void init(){ 8 memset(a,0,sizeof(a)); 9 } 10 //插入 11 bool insert_(ll x){ 12 for(int

BZOJ 3105: [cqoi2013]新Nim游戏 [高斯消元XOR 线性基]

以后我也要用传送门! 题意:一些数,选择一个权值最大的异或和不为0的集合 终于有点明白线性基是什么了...等会再整理 求一个权值最大的线性无关子集 线性无关子集满足拟阵的性质,贪心选择权值最大的,用高斯消元判断是否和已选择的线性相关 每一位记录pivot[i]为i用到的行 枚举要加入的数字的每一个二进制为1的位,如果有pivot[i]那么就异或一下(消元),否则pivot[i]=这个数并退出 如果最后异或成0了就说明线性相关... #include <iostream> #include &l

[bzoj 2460]线性基+贪心

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2460 网上很多题目都没说这个题目的证明,只说了贪心策略,我比较愚钝,在大神眼里的显然的策略还是想证明一下才安心--所以这里记录一下证明过程. 贪心策略:按魔力值从大到小排序,从大往小往线性基里插,如果成功插入新元素,就选这个,如果插不进去,就不选这个. 证明: 设有n个材料,每个材料的属性值是x[1],x[2],...,x[n],魔力值是v[1],v[2],...,v[n],这里假设v已

bzoj 2460: [BeiJing2011]元素【线性基+贪心】

先按魔力值从大到小排序,然后从大到小插入线性基中,如果插入成功就加上这个魔力值 因为线性基里是没有异或和为0的集合的,所以正确性显然,然后最优性,考虑放进去一个原来没选的,这样为了可行性就要删掉一个,又因为是从大到小加进去的,所以删掉的这个魔力值一定是大于加进去的,所以不优,所以贪心构造的就是最优解 #include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int

bzoj 4269 再见Xor 线性基

题面 题目传送门 解法 第一问就是线性基的裸题 第二问也很类似,从低位向高位枚举,如果线性基上这一位有数,那么直接异或后返回 时间复杂度:\(O(n\ log\ a_i)\) 代码 #include <bits/stdc++.h> #define int long long using namespace std; template <typename node> void chkmax(node &x, node y) {x = max(x, y);} template

【BZOJ-2460&amp;3105】元素&amp;新Nim游戏 动态维护线性基 + 贪心

3105: [cqoi2013]新Nim游戏 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 839  Solved: 490[Submit][Status][Discuss] Description 传统的Nim游戏是这样的:有一些火柴堆,每堆都有若干根火柴(不同堆的火柴数量可以不同).两个游戏者轮流操作,每次可以选一个火柴堆拿走若干根火柴.可以只拿一根,也可以拿走整堆火柴,但不能同时从超过一堆火柴中拿.拿走最后一根火柴的游戏者胜利. 本题的游戏

【BZOJ-2115】Xor 线性基 + DFS

2115: [Wc2011] Xor Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 2142  Solved: 893[Submit][Status][Discuss] Description Input 第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目. 接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si 与Ti之间存在 一条权值为 Di的无向边. 图中可能有重边或自环. Output 仅包含一个整数,表示最大