zoukankan      html  css  js  c++  java
  • 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和最大,所以必然我们要想办法处理环的情况。我的做法是任意地先找出一条从1到n的路径,把这条路径上的xor和作为ans初值(先不管为什么可行),然后我们的任务就变成了求若干个环与这个ans初值所能组合成的xor最大值。显然,我们需要预处理出图上所有的环,并处理出所有环的环上xor值,这当然是dfs寻找,到n的路径的时候顺便求一下就可以了。

      当我们得到了若干个环的xor值之后,因为是要求xor最大值,我们就可以构出这所有xor值的线性基。构出之后,再用ans在线性基上取max就可以了。

    为什么可以这么做? 证明在上面大牛博客里有证明。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int maxn = 50010;
    const int maxm = 200010;
    int n, m, edgecnt;
    int head[maxn];
    bool vis[maxn];
    LL dx[maxn];
    LL p[70];
    LL circle[maxm], ans;
    void init(){
        memset(head, -1, sizeof(head));
        edgecnt = 0;
    }
    struct edge{
        int to,next;
        LL w;
        edge(){}
        edge(int to, int next, LL w):to(to),next(next),w(w){}
    }E[maxm];
    int cnt = 0;
    void add(int u, int v, LL w){
        E[edgecnt].to = v, E[edgecnt].next = head[u], E[edgecnt].w = w, head[u] = edgecnt++;
    }
    void dfsloop(int x){
        vis[x] = 1;
        for(int i=head[x]; i+1; i=E[i].next){
            int to = E[i].to;
            if(!vis[to]) dx[to] = dx[x]^E[i].w, dfsloop(to);
            else{
                circle[++cnt] = dx[to]^dx[x]^E[i].w;
            }
        }
    }
    
    int main()
    {
        int x,y;
        LL z;
        init();
        scanf("%d %d", &n,&m);
        for(int i=1; i<=m; i++){
            scanf("%d %d %lld", &x,&y,&z);
            add(x, y, z);
            add(y, x, z);
        }
        dfsloop(1);
        ans = dx[n];//任取一条从1到n的路径,并得到其xor和
        for(int i=1; i<=cnt; i++){
            for(int j=62; j>=0; j--){
                if(!(circle[i]>>j)) continue;
                if(!p[j]){
                    p[j] = circle[i];
                    break;
                }
                circle[i] ^= p[j];
            }
        }
         //for(int i=62;i>=0;i--) if(!(ans>>i)) ans^=p[i];
         //ans有初值,不能直接根据这一位是否为0来判断是否更大,max更为稳妥
         for(int i=62; i>=0; i--){
            if((ans^p[i])>ans){
                ans = ans^p[i];
            }
         }
         printf("%lld
    ", ans);
         return 0;
    }
    
  • 相关阅读:
    Python 学习日记 第七天
    Python 学习日记 第六天
    Python 学习日记 第五天
    Python 学习日记 第四天
    Redis 中的数据类型及基本操作
    Asp.net mvc 中View 的呈现(二)
    Asp.net mvc 中View的呈现(一)
    Asp.net mvc 中Action 方法的执行(三)
    Asp.net mvc 中Action 方法的执行(二)
    Asp.net mvc 中Action 方法的执行(一)
  • 原文地址:https://www.cnblogs.com/spfa/p/7449907.html
Copyright © 2011-2022 走看看