[WC2011]最大XOR和路徑(線性基)

P4151 [WC2011]最大XOR和路徑

題目描述

XOR(異或)是一種二元邏輯運算,其運算結果當且僅當兩個輸入的布爾值不相等時才爲真,不然爲假。 XOR 運算的真值表以下( 1 表示真, 0 表示假):node

QQ20180128145629.png

而兩個非負整數的 XOR 是指將它們表示成二進制數,再在對應的二進制位進行 XOR 運算。ios

譬如 12 XOR 9 的計算過程以下:spa

QQ20180128145728.png

故 12 XOR 9 = 5 。code

容易驗證, XOR 運算知足交換律與結合律,故計算若干個數的 XOR 時,不一樣的計算順序不會對運算結果形成影響。從而,能夠定義 KK 個非負整數 $A_1$,$A_2$​ ,$……$ , $A_{K-1}$​,$A_K$的 XOR 和爲 $A_1$ XOR $A_2$ XOR …… XOR $A_{K-1}$ XOR $A_K$get

考慮一個邊權爲非負整數的無向連通圖,節點編號爲 1 到 N ,試求出一條從 1 號節點到 N 號節點的路徑,使得路徑上通過的邊的權值的 XOR 和最大。string

路徑能夠重複通過某些點或邊,當一條邊在路徑中出現了屢次時,其權值在計算 XOR 和時也要被計算相應多的次數,具體見樣例。it

輸入輸出格式

輸入格式:io

輸入文件 xor.in 的第一行包含兩個整數 $N$ 和 $M$ , 表示該無向圖中點的數目與邊的數目。class

接下來 M 行描述 M 條邊,每行三個整數 $S_i$​ , $T_i$​ , $D_i$ , 表示 $S_i$ 與 $T_i$ 之間存在一條權值爲 $D_i$ 的無向邊。stream

圖中可能有重邊或自環。

輸出格式:

輸出文件 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

說明

【樣例說明】

QQ20180128150132.png

如圖,路徑 $1 \rightarrow 2 \rightarrow 4 \rightarrow 3 \rightarrow 5 \rightarrow 2 \rightarrow 4 \rightarrow 5$對應的XOR和爲

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

固然,一條邊數更少的路徑 $1 \rightarrow 3 \rightarrow 5$ 對應的XOR和也是 2 XOR 4 = 6 。

【數據規模】

對於 $20 %$ 的數據, $N \leq 100$ , $M \leq 1000$ , $D_i$ $\leq$ $10^{4}$ ;

對於 $50 %$ 的數據, $N \leq 1000$ , $M \leq 10000$ , $D_i$ $\leq$ $10^{18}$ ;

對於 $70 %$ 的數據, $N \leq 5000$ , $M$ $\leq$ $50000$ , $D_i$ $\leq$ $10^{18}$ ;

對於 $100 %$ 的數據, $N \leq 50000$ , $M \leq 100000$ , $D_i \leq 10^{18}$ 。


<font color="00ccff">題解</font>

怎麼說呢。有這樣一條定理 (不知道這個以前的我根本不會作這道題)

  • 任意一條 $1$ 到 $n$ 的路徑的異或和,均可以由任意一條 $1$ 到 $n$ 路徑的異或和與圖中的一些環的異或和來組合獲得。

爲何? 若是咱們走一條路徑的話,若是路徑上存在一個環,那麼這個環的總異或值就能夠下放到線性基。由於把這個環走兩遍就等於沒走這個環,一樣我若是是由一條路徑到的這個環,沿原路返回,那等於那條路徑沒走,只走了環。

在這種條件下,咱們能夠考慮把環儲存爲一個線性基的元素。由於這個元素是可選和可不選的。

那麼爲何是任意的簡單路徑呢? 由於 $1$ 到 $N$ 的簡單路徑是必需要走的。這顯然。 而後若是有多條 $1$ 到 $N$ 的路徑,那麼這顯然也構成一個環,也是能夠抵消異或的任意一條其餘的路徑的是吧。 而後這個題目就好作了咕咕咕。


<font color="00ccff">代碼</font>

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#define ll long long
using namespace std;
ll dis[50001],sum[101],b[101];
ll n,m,vis[50001];
int head[100001],num;
struct node{
    int next,to;
    ll v;
}e[100001<<1];

ll read()
{
    ll x=0,w=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*w;
}

void add(int from,int to,ll v){
    num++;
    e[num].to=to;
    e[num].v=v;
    e[num].next=head[from];
    head[from]=num;
}

void update(ll x){
    for(int i=60;i>=0;i--){
        if(sum[i]&x){
            if(b[i])x^=b[i];
            else {
                b[i]=x;
                break;
            }
        }
    }
}

void dfs(int x){
    vis[x]=1;
    for(int i=head[x];i;i=e[i].next){
        int v=e[i].to;
        if(vis[v])update(dis[v]^e[i].v^dis[x]);
        else dis[v]=dis[x]^e[i].v,dfs(v);
    }
}

ll query(ll x){
    ll ans=x;
    for(int i=60;i>=0;i--){
        if((ans^b[i])>ans)ans^=b[i];
    }
    return ans;
}

int main()
{
    n=read();m=read();
    sum[0]=1;for(int i=1;i<=60;i++)sum[i]=sum[i-1]*2;
    for(int i=1;i<=m;i++){
        ll x=read(),y=read(),z=read();
        add(x,y,z);add(y,x,z);
    }
    dfs(1);
    printf("%lld",query(dis[n]));
    return 0;
}
相關文章
相關標籤/搜索