1. 程式人生 > >51nod1312 最大異或和

51nod1312 最大異或和

out opcode 輸出 () 不一定 stream 操作 ref output

題目來源: TopCoder 基準時間限制:1 秒 空間限制:131072 KB 分值: 320 有一個正整數數組S,S中有N個元素,這些元素分別是S[0],S[1],S[2]...,S[N-1]。現在你可以通過一個操作來更新數組。操作方法如下: 選擇兩個不同的數i、j(0<=i,j<N 且 i!=j),先計算A = S[i] xor S[j], B = S[j]。然後用A、B替換S[i],S[j],即 S[i]=A , S[j]=B。其中xor表示異或運算。 你可以進行任意多次操作,問最後生成的數組S的元素和 SUM = S[0]+S[1]+S[2]+...+S[N-1] 最大可能值是多少。輸出這個最大值。
例如:S = {1,0},去A = S[1] xor S[0] = 1,B = S[0] = 1,新的S={1,1},SUM = 1+1 = 2. Input
第一行一個整數N,且1<=N<=50
接下來N行每行一個整數S[i],且0<=S[i]<=1,000,000,000,000,000 (10^15)
Output
一個整數,即最後集合可能的最大值SUM。
Input示例
3
1
2
3
Output示例
8

數學問題 線性基 貪心

顯然就是線性基。

假設我們需要k個數來搞出線性基,那麽有n-k個數可以取到異或空間裏的最大值max。

這k個數線性無關,為了使他們最大,我們先把它們消到盡可能小,再異或max。

↑把得到的n個數累加起來就是答案。

秒題三分鐘,寫題一小時?exm?

動態維護線性基看上去並沒有問題,然而交上去無限WAWAWA。

然後突然意識到年初的時候和Sfailsth討論過的問題:高斯消元得到的線性基向量一定是該位為1的所有可能得到的向量中最小的,而動態維護線性基得到不一定是最小的。

丟一個鏈接:http://www.cnblogs.com/SfailSth/p/6220328.html

於是手動把線性基向量消到最小,AC

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4
#include<cstdio> 5 #include<cmath> 6 #define LL long long 7 using namespace std; 8 const int mxn=65; 9 LL read(){ 10 LL x=0,f=1;char ch=getchar(); 11 while(ch<0 || ch>9){if(ch==-)f=-1;ch=getchar();} 12 while(ch>=0 && ch<=9){x=x*10+ch-0;ch=getchar();} 13 return x*f; 14 } 15 int n; 16 LL a[mxn],b[mxn],f[mxn]; 17 int main(){ 18 int i,j; 19 n=read(); 20 for(i=1;i<=n;i++)a[i]=b[i]=read(); 21 for(i=1;i<=n;i++) 22 for(j=62;j>=0;j--){ 23 if((b[i]>>j)&1){ 24 if(!f[j]){f[j]=b[i];break;} 25 b[i]^=f[j]; 26 } 27 } 28 LL mx=0;int cnt=0; 29 for(i=62;i>=0;i--) 30 if(f[i]){ 31 if((mx^f[i])>mx){mx^=f[i];} 32 cnt++; 33 } 34 LL ans=0; 35 ans+=mx*(n-cnt+1); 36 cnt--; 37 for(i=0;cnt && i<=62;i++){ 38 if(f[i]){ 39 for(int j=i-1;j>=0;j--){ 40 if(f[j] && ((f[i]>>j)&1)){ 41 f[i]^=f[j]; 42 } 43 } 44 ans+=mx^f[i]; 45 cnt--; 46 } 47 } 48 printf("%lld\n",ans); 49 return 0; 50 }

51nod1312 最大異或和