bzoj 2115 [Wc2011] Xor

http://www.elijahqi.win/archives/3453
题目描述

XOR(异或)是一种二元逻辑运算,其运算结果当且仅当两个输入的布尔值不相等时才为真,否则为假。 XOR 运算的真值表如下(

1
1 表示真,

0
0 表示假):

而两个非负整数的 XOR 是指将它们表示成二进制数,再在对应的二进制位进行 XOR 运算。

譬如

12
12 XOR

9
9 的计算过程如下:

12
12 XOR

9 = 5
9=5 。

容易验证, XOR 运算满足交换律与结合律,故计算若干个数的 XOR 时,不同的计算顺序不会对运算结果造成影响。从而,可以定义

K
K 个非负整数

A_1
A1​ ,

A_2
A2​ ,……,

A_{K-1}
AK−1​ ,

A_K
AK​ 的 XOR 和为

A_1
A1​ XOR

A_2
A2​ XOR …… XOR

A_{K-1}
AK−1​ XOR

A_K
AK​

考虑一个边权为非负整数的无向连通图,节点编号为

1
1 到

N
N ,试求出一条从

1
1 号节点到

N
N 号节点的路径,使得路径上经过的边的权值的 XOR 和最大。

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

输入输出格式

输入格式:
输入文件 xor.in 的第一行包含两个整数

N
N 和

M
M , 表示该无向图中点的数目与边的数目。

接下来

M
M 行描述

M
M 条边,每行三个整数

S_i
Si​ ,

T_i
Ti​ ,

D_i
Di​ , 表示

S_i
Si​ 与

T_i
Ti​ 之间存在一条权值为

D_i
Di​ 的无向边。

图中可能有重边或自环。

输出格式:
输出文件 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
说明

【样例说明】

如图,路径

1 \rightarrow 2 \rightarrow 4 \rightarrow 3 \rightarrow 5 \rightarrow 2 \rightarrow 4 \rightarrow 5
1→2→4→3→5→2→4→5 对应的XOR和为

2
2 XOR

1
1 XOR

2
2 XOR

4
4 XOR

1
1 XOR

1
1 XOR

3 = 6
3=6

当然,一条边数更少的路径

1 \rightarrow 3 \rightarrow 5
1→3→5 对应的XOR和也是

2
2 XOR

4 = 6
4=6 。

【数据规模】

对于

20 \%
20% 的数据,

N \leq 100
N≤100 ,

M \leq 1000
M≤1000 ,

D_i \leq 10^{4}
Di​≤104 ;

对于

50 \%
50% 的数据,

N \leq 1000
N≤1000 ,

M \leq 10000
M≤10000 ,

D_i \leq 10^{18}
Di​≤1018 ;

对于

70 \%
70% 的数据,

N \leq 5000
N≤5000 ,

M \leq 50000
M≤50000 ,

D_i \leq 10^{18}
Di​≤1018 ;

对于

100 \%
100% 的数据,

N \leq 50000
N≤50000 ,

M \leq 100000
M≤100000 ,

D_i \leq 10^{18}
Di​≤1018 。

首先找到一条1~n的路径 然后把图中所有的环都找出来 插入线性基 然后到时候就用所有的环和1~n的路径贪心xor即可

正确性 首先所有路径都可以表示成过环或者不过 这个如何来看假设环很远 那么我可以到环再走回来看作权值为环xor上路径即可

另外是否任选都可以 考虑如果有两条路径的话 那么他们之间一定会构成环 那么考虑经过这个环然后再走回去再走新的路相当于把原来的路都异或掉了 相当于也是选择了这条路 然后走另外一个环于是可以同理做

#include<cstdio>
#include<cctype>
#include<algorithm>
#define ll long long
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if(T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline ll read(){
    ll x=0,f=1;char ch=gc();
    while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
    return x*f;
}
const int N=5e4+10;
struct node{
    int y,next;ll z;
}data[N<<2];
ll cir[N<<3],dis[N],s[70];int h[N],num,n,m;bool visit[N];
inline void dfs(int x){visit[x]=1;//printf("%d ",x);
    for (int i=h[x];i;i=data[i].next){
        int y=data[i].y;if(visit[y]){//puts("");printf("%d\n",y);puts("--");
            cir[++num]=dis[y]^dis[x]^data[i].z;
            continue;
        }dis[y]=dis[x]^data[i].z;dfs(y);
    }
}
int main(){
//  freopen("bzoj2115.in","r",stdin);
    n=read();m=read();
    for (int i=1;i<=m;++i){
        int x=read(),y=read();ll z=read();
        data[++num].y=y;data[num].next=h[x];h[x]=num;data[num].z=z;
        data[++num].y=x;data[num].next=h[y];h[y]=num;data[num].z=z;
    }num=0;dfs(1);ll ans=dis[n];//puts("");
    //for (int i=1;i<=n;++i) printf("%lld ",dis[i]);puts("");
    //for (int i=1;i<=num;++i) printf("%lld ",cir[i]);
    sort(cir+1,cir+num+1);num=unique(cir+1,cir+num+1)-cir-1;
    for (int i=1;i<=num;++i) {
        for (int j=60;~j;--j){
            if (!(cir[i]&(1LL<<j))) continue;
            if (!s[j]){s[j]=cir[i];break;}
            cir[i]^=s[j];
        }
    }
    for (int i=62;~i;--i){
        if((ans^s[i])>ans) ans=ans^s[i];
    }printf("%lld\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值