zoukankan      html  css  js  c++  java
  • BZOJ_2115 [Wc2011] Xor 【图上线性基】

    一、题目

      [Wc2011] Xor

    二、分析

      比较有意思的一题,这里也学到一个结论:$1$到$N$的任意一条路径异或和,可以是一个任意一条$1$到$N$的异或和与图中一些环的异或和组合得到。因为一个数异或自己等于$0$。

      对于这题,需要把所有的简单环先全部求出来,可以用$DFS$,然后用任意一条$1$到$N$的路径和的值与所有简单环的异或的值一起构造线性基(如果有不在路径上的环也没关系,可以走到这个环的位置再回来,相当于到这个环起点的这条路径走了两次,异或一下就抵消了),然后就是求最大值了。

    三、AC代码

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 #define ll long long
     5 #define Min(a,b) ((a)>(b)?(b):(a))
     6 #define Max(a,b) ((a)>(b)?(a):(b))
     7 const int maxn = 5e4 + 13;
     8 const int MAXL = 60;
     9 
    10 struct edge
    11 {
    12     int to, rev;
    13     ll cost;
    14     edge(){}
    15     edge(int to, ll cost, int rev){
    16         this->to = to;
    17         this->cost = cost;
    18         this->rev = rev;
    19     }
    20 };
    21 vector<edge> G[maxn];
    22 ll sum[maxn], ans[maxn<<3], base[MAXL + 2];
    23 int cnt;
    24 bool flag[maxn];
    25 
    26 void dfs(int s, int rev)
    27 {
    28     flag[s] = 1;   
    29     for(int i = 0; i < G[s].size(); i++) {
    30         edge e = G[s][i];
    31         if(rev != i) {
    32             if(!flag[e.to]) {
    33                 sum[e.to] = sum[s]^e.cost;
    34                 dfs(e.to, e.rev);
    35             }
    36             else {
    37                 //记录环的异或值
    38                 ans[cnt++] = sum[e.to]^sum[s]^e.cost;
    39             }
    40         }
    41     }
    42 }
    43 
    44 void getbase()
    45 {
    46     memset(base, 0, sizeof(base));
    47     for(int i = 0; i < cnt; i++) {
    48         for(int j = MAXL; j >= 0; j--) {
    49             if( (ans[i]>>j) & 1) {
    50                 if(base[j]) {
    51                     ans[i] = ans[i]^base[j];
    52                 }
    53                 else {
    54                     base[j] = ans[i];
    55                     for(int k = j - 1; k >= 0; k--)
    56                         if( (base[j]>>k) & 1)
    57                             base[j] ^= base[k];
    58                     for(int k = j + 1; k <= MAXL; k++)
    59                         if( (base[k]<<j) & 1)
    60                             base[k] ^= base[j];
    61                     break;
    62                 }
    63             }
    64         }
    65     }
    66 }
    67 
    68 int main()
    69 {
    70     freopen("input.txt", "r", stdin);
    71     int n, m, from, to;
    72     ll D;
    73     edge e;
    74     scanf("%d%d", &n, &m);
    75     for(int i = 0; i < m; i++) {
    76         scanf("%d%d%lld", &from, &to, &D);
    77         G[from].push_back(edge(to, D, G[to].size() ));
    78         G[to].push_back(edge(from, D, G[from].size() - 1));
    79     }
    80     memset(sum, 0, sizeof(sum));
    81     memset(flag, 0, sizeof(flag));
    82     cnt = 0;
    83     dfs(1, -1);
    84     getbase();
    85     ll Ans = sum[n];
    86     for(int i = MAXL; i >= 0; i--) {
    87         if(Ans < (Ans^base[i]) )
    88             Ans ^= base[i];
    89     }
    90     printf("%lld
    ", Ans);
    91     return 0;
    92 }
  • 相关阅读:
    PHP处理字符中的emoji表情
    CentOS 7 安装 PHP7.2 (LNMP环境搭建第二步)
    php 二维数组按某个字段排序
    JavaScript返回到上一页的方法
    常用正则表达式—手机号码
    JS实现斐波那契列数的三种方法
    常用正则表达式--金额
    PHP中三种设置脚本最大执行时间的方法
    生成指定长度随机字符串
    API常用签名验证方法(PHP实现)
  • 原文地址:https://www.cnblogs.com/dybala21/p/11366724.html
Copyright © 2011-2022 走看看