BZOJ2115 [Wc2011] Xor


本文版權歸ljh2000和博客園共有,歡迎轉載,但須保留此聲明,並給出原文鏈接,謝謝合作。

 

 

本文作者:ljh2000 
作者博客:http://www.cnblogs.com/ljh2000-jump/
轉載請注明出處,侵權必究,保留最終解釋權!

 

Description

Input

第一行包含兩個整數N和 M, 表示該無向圖中點的數目與邊的數目。 接下來M 行描述 M 條邊,每行三個整數Si,Ti ,Di,表示 Si 與Ti之間存在 一條權值為 Di的無向邊。 圖中可能有重邊或自環。

Output

僅包含一個整數,表示最大的XOR和(十進制結果),注意輸出后加換行回車。

Sample Input

5 7
1 2 2
1 3 2
2 4 1
2 5 1
4 5 3
5 3 4
4 3 2

Sample Output

6

HINT

 

 

正解:dfs+線性基

解題報告:

  繼續刷線性基...

  這道題要求從1到n的最大xor和路徑,存在重邊,允許經過重復點、重復邊。那么在圖上作圖嘗試之后就會發現,路徑一定是由許多的環和一條從1到n的路徑組成。容易發現,來回走是沒有任何意義的,因為來回走意味着抵消。考慮這道題求得是路徑xor和最大,所以必然我們要想辦法處理環的情況。我的做法是任意地先找出一條從1到n的路徑,把這條路徑上的xor和作為ans初值(先不管為什么可行),然后我們的任務就變成了求若干個環與這個ans初值所能組合成的xor最大值。顯然,我們需要預處理出圖上所有的環,並處理出所有環的環上xor值,這當然是dfs尋找,到n的路徑的時候順便求一下就可以了。

  當我們得到了若干個環的xor值之后,因為是要求xor最大值,我們就可以構出這所有xor值的線性基。構出之后,再用ans在線性基上取max就可以了。

  現在我們來討論上述做法的可行性。

  第一種情況:我們對最終答案產生貢獻的某個環離1到n的主路徑很遠,這樣的話,因為至少可以保證1可以到達這個環,那么我們可以走到這個環之后繞環一周之后原路返回,這樣從1走到環的路上這一段被重復經過所以無效,但是環上的xor值被我們得到了,所以我們並不關心這個環和主路徑的關系,我們只關心環的權值。

  第二種情況:我們任意選取的到n的路徑是否能保證最優性。假設存在一條更優的路徑從1到n,那么這條路徑與我們原來的路徑構成了一個環,也就會被納入線性基中,也會被計算貢獻,假如這個環會被經過,那么最后的情況相當於是走了兩遍原來選取的路徑,抵消之后走了一次這個最優路徑,所以我們無論選取的是哪條路徑作為ans初值,都可以通過與更優情況構成環,然后得到一樣的結果。這一證明可以拓展到路徑上的任意點的路徑選取。

  這樣我們就可以完美解決了。我第一次WA了一發,因為我沒有考慮到ans初值不為0,在線性基上取到xor的max的時候,不能單純以ans這一位是否為0來決定是否異或上基的這一位,必須要看異或之后取一個max做一個判斷才行。

 

 1 //It is made by jump~
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <ctime>
 9 #include <vector>
10 #include <queue>
11 #include <map>
12 #include <set>
13 using namespace std;
14 typedef long long LL;
15 const int MAXN = 50011;
16 const int MAXM = 200011;
17 int n,m,ecnt;
18 int first[MAXN],next[MAXM],to[MAXM];
19 LL w[MAXM],dx[MAXN];
20 bool vis[MAXN];
21 int cnt;
22 LL circle[MAXM],ans;//經過每個環可獲得的的權值
23 LL p[63];
24 
25 inline int getint(){int w=0,q=0;char c=getchar();while((c<'0'||c>'9')&&c!='-')c=getchar();if(c=='-')q=1,c=getchar();while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w;}
26 inline LL getlong(){LL w=0,q=0;char c=getchar();while((c<'0' || c>'9')&&c!='-')c=getchar();if(c=='-') q=1,c=getchar();while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w;}
27 
28 inline void dfs(int x){
29     vis[x]=1;
30     for(int i=first[x];i;i=next[i]) {
31     int v=to[i]; 
32     if(!vis[v]) dx[v]=dx[x]^w[i],dfs(v);
33     else circle[++cnt]=dx[v]^dx[x]^w[i];
34     }
35 }
36 
37 inline void work(){
38     n=getint(); m=getint(); int x,y; LL z;
39     for(int i=1;i<=m;i++) {
40     x=getint(); y=getint(); z=getlong();
41     next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; w[ecnt]=z;
42     next[++ecnt]=first[y]; first[y]=ecnt; to[ecnt]=x; w[ecnt]=z;
43     }
44     dfs(1);
45     ans=dx[n];//任取一條從1到n的路徑,並得到其xor和
46     for(int i=1;i<=cnt;i++)//構造線性基
47     for(int j=62;j>=0;j--) {
48         if(!(circle[i]>>j)) continue;
49         if(!p[j]) { p[j]=circle[i]; break; }
50         circle[i]^=p[j];
51     }
52     //for(int i=62;i>=0;i--) if(!(ans>>i)) ans^=p[i];
53     //ans有初值,不能直接根據這一位是否為0來判斷是否更大,max更為穩妥
54     for(int i=62;i>=0;i--) if((ans^p[i])>ans) ans=ans^p[i];//從線性基中得到最大值
55     printf("%lld",ans);
56 }
57 
58 int main()
59 {
60   work();
61   return 0;
62 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM