我是靠谱客的博主 无私紫菜,最近开发中收集的这篇文章主要介绍洛谷 P4151 [WC2011]最大XOR和路径 线性基,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

题目描述
XOR(异或)是一种二元逻辑运算,其运算结果当且仅当两个输入的布尔值不相等时才为真,否则为假。 XOR 运算的真值表如下( 1 1 表示真, 0 表示假):
这里写图片描述
而两个非负整数的 XOR 是指将它们表示成二进制数,再在对应的二进制位进行 XOR 运算。
譬如 12 12 XOR 9 9 的计算过程如下:
这里写图片描述
12 XOR 9=5 9 = 5
容易验证, XOR 运算满足交换律与结合律,故计算若干个数的 XOR 时,不同的计算顺序不会对运算结果造成影响。从而,可以定义 K K 个非负整数 A1A2AK1AK的 XOR 和为 A1 A 1 XOR A2 A 2 XOR …… XOR AK1 A K − 1 XOR AK A K

考虑一个边权为非负整数的无向连通图,节点编号为 1 1 N ,试求出一条从 1 1 号节点到 N 号节点的路径,使得路径上经过的边的权值的 XOR 和最大。

路径可以重复经过某些点或边,当一条边在路径中出现了多次时,其权值在计算 XOR 和时也要被计算相应多的次数,具体见样例。

输入输出格式

输入格式:
输入文件 xor.in 的第一行包含两个整数 N N M , 表示该无向图中点的数目与边的数目。
接下来 M M 行描述 M 条边,每行三个整数 SiTiDi S i , T i , D i ,表示 Si S i Ti T i 之间存在一条权值为 Di D i 的无向边。
图中可能有重边或自环。

输出格式:
输出文件 xor.out 仅包含一个整数,表示最大的 XOR 和(十进制结果)。

输入输出样例

输入样例#1:
5 7
1 2 2
1 3 2
2 4 1
2 5 1
4 5 3
5 3 4
4 3 2
输出样例#1:
6
说明

【样例说明】
这里写图片描述
如图,路径 12435245 1 → 2 → 4 → 3 → 5 → 2 → 4 → 5 对应的XOR和为

2 2 XOR 1 XOR 2 2 XOR 4 XOR 1 1 XOR 1 XOR 3=6 3 = 6

当然,一条边数更少的路径 135 1 → 3 → 5 对应的XOR和也是 2 2 XOR 4=6

【数据规模】

对于 20% 20 % 的数据, N100M1000Di104 N ≤ 100 , M ≤ 1000 , D i ≤ 10 4

对于 50% 50 % 的数据, N1000M10000Di1018 N ≤ 1000 , M ≤ 10000 , D i ≤ 10 18

对于 70% 70 % 的数据, N5000M50000Di1018 N ≤ 5000 , M ≤ 50000 , D i ≤ 10 18

对于 100% 100 % 的数据, N50000M100000Di1018 N ≤ 50000 , M ≤ 100000 , D i ≤ 10 18

分析:
一堆数的异或和就可以考虑线性基了,因为线性基只有 log2Di l o g 2 D i ,也就是最多 64 64 个。我们发现,任意路径都可以表示为一条从 1 1 n的简单路径加若干个环。
如果 1 1 n的简单路径与某个环有边相交,相当于另一条简单路径。
如果一个环不在路径上,我们可以先走到这个环上,转一圈后原路返回,走两次的边就被抵消了。
如果两个环有交,那么相当于一个新的环。
所以我们枚举环,加入到线性基里,然后取异或最大值,从高位开始算,因为某一位能拿到 1 1 比这位拿到0一定更优。
至于枚举环,我们可以建一棵dfs搜索树,对于任何一条非树边,与树上路径连成一个环,这些环可以代替所有环。因为假设我们有一个一条非树边 (x,y) ( x , y ) 加上 x x y树上路径的环和一个一条非树边 (y,z) ( y , z ) 加上 y y z树上路径的环,异或起来就是一个 (x,z) ( x , z ) 树上路径+若干 (x,z) ( x , z ) 非树边连成路径的环。

代码:

#include <iostream>
#include <cmath>
#include <cstdio>
#define LL long long

const int maxn=5e4+7;
const int maxe=1e5+7;
const int maxp=62;

using namespace std;

int n,m,x,y;
int ls[maxn],vis[maxn];
LL dis[maxn],a[maxn],bit[maxn];
LL ans,w;

struct edge{
    int y,next;
    LL w;
}g[maxe*2];

void push(LL x)
{
    if (x==0) return;
    int c=0;
    for (int i=1;i<=maxp;i++)
    {
        if (x&bit[maxp-i])
        {
            if ((!a[i]) && (!c)) c=i;
            x^=a[i];
        }
    }
    a[c]=x;
    for (int i=1;i<=maxp;i++)
    {
        if (i==c) continue;
        if (a[i]&bit[maxp-c]) a[i]^=a[c];
    }
}

void dfs(int x,LL rec)
{
    dis[x]=rec;
    vis[x]=1;
    for (int i=ls[x];i>0;i=g[i].next)
    {
        int y=g[i].y;
        if (!vis[y]) dfs(y,rec^g[i].w);
                else push(rec^g[i].w^dis[y]);
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%lld",&x,&y,&w);
        g[i].y=y;
        g[i].w=w;
        g[i].next=ls[x];
        ls[x]=i;
        g[i+m].y=x;
        g[i+m].w=w;
        g[i+m].next=ls[y];
        ls[y]=i+m;
    }
    bit[0]=1;
    for (int i=1;i<=maxp;i++) bit[i]=bit[i-1]*2;
    dfs(1,0);
    ans=dis[n];
    for (int i=1;i<=maxp;i++) ans=max(ans,ans^a[i]);
    printf("%lld",ans);
}

最后

以上就是无私紫菜为你收集整理的洛谷 P4151 [WC2011]最大XOR和路径 线性基的全部内容,希望文章能够帮你解决洛谷 P4151 [WC2011]最大XOR和路径 线性基所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(44)

评论列表共有 0 条评论

立即
投稿
返回
顶部