• 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;
    }
    
  • 相关阅读:
    常用函数集锦
    HDU1212加深下对取模运算的理解
    HDU1022 queue和vector模拟
    设计模式原则
    3.6html学习笔记之样式选择
    poj 1274(二分图最大匹配)
    poj 1469(二分图最大匹配)
    poj 3692(二分图匹配--最大独立集)
    Codeforces Round #230 (Div. 1) 解题报告
    Codeforces Rockethon 2014 解题报告
  • 原文地址:https://www.cnblogs.com/spfa/p/7449907.html
Copyright © 2020-2023  润新知