Xor Sum
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Others)
Total Submission(s): 1555 Accepted Submission(s): 657
輸入的第一行是一個整數T(T < 10),表示共有T組數據。
每組數據的第一行輸入兩個正整數N,M(<1=N,M<=100000),接下來一行,包含N個正整數,代表 Zeus 的獲得的集合,之后M行,每行一個正整數S,代表 Prometheus 詢問的正整數。所有正整數均不超過2^32。
對於每個詢問,輸出一個正整數K,使得K與S異或值最大。
題目鏈接:HDU 4825
學習這個也學了挺久的,苦於能百度到的詳細資料甚少,尤其很多是用靜態數組開寫的(節省內存看起來有一點麻煩),好像這題沒看見用動態鏈表來寫的(目前還是入門階段就一直用着new或malloc寫),今天看了好一會兒的代碼終於看出一點頭緒了
題目本身非常經典,就是給一堆數(就記為 Xi 吧)又給Q個詢問,每次又給出一個特定的數S,求(Xi^S)的最大值。
首先異或就是兩個二進制位置上的數不同就可以得到1相同則得到0,比如(10100)2^(01111)2=(11011)2,可以轉換成十進制驗證:20^15=27。
然后把每一個數都轉換成二進制(位置要對齊,前面不足則補0),轉換的長度就跟題目給的數據范圍有關了,此題就33位就夠了。更新字典樹的順序和過程與普通單詞字典樹一模一樣,從左到右地遍歷插入各位二進制數值,但顯然next指針只有兩個——next[0]與next[1],更新的最后把原來的值附到結尾節點的val上,表示這整條路對應的十進制是val。
然后如何求最大異或值呢,先要知道一般情況下正項等比數列前n-1項求和的值肯定要小於第n項的值,那也就是說最壞情況下走第x個節點而x+1~n均只能得到0的時候,也比不走x而x+1~n均得到1的情況好。
然后假設已經得到了最大異或值Max,那Max異或K就可以得到某個數Xi了,此時不知道Xi是什么,但是可以通過貪心找到它。
貪心從最高位也就是樹的開始位置直接往當前二進制位值取反的節點走,走到底那個節點的val就是我們要找的Xi,這里我直接用bitset來代替位運算直觀一點
代碼:
#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define CLR(x,y) memset(x,y,sizeof(x))
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
typedef pair<int,int> pii;
typedef long long LL;
const double PI=acos(-1.0);
const int N=33;
struct info
{
info *nxt[2];
int val;
info()
{
val=0;
fill(nxt,nxt+2,nullptr);
}
};
info *L;
void update(int n)
{
bitset<N> bit=n;
int i,indx;
info *cur=L;
for (i=32; i>=0; --i)
{
indx=bit[i];
if(!cur->nxt[indx])
{
info *one=new info();
cur->nxt[indx]=one;
cur=one;
}
else
cur=cur->nxt[indx];
}
cur->val=n;//末位置節點附着
}
int query(int k)
{
bitset<N> bit=k;
info *cur=L;
int indx,i;
for (i=32; i>=0; --i)
{
indx=bit[i];
if(cur->nxt[indx^1])//往取反位置走
cur=cur->nxt[indx^1];
else
cur=cur->nxt[indx];//沒有的話只能繼續往前走
}
return cur->val;
}
void desinfo(info *cur)//刪除字典樹釋放內存防止MLE
{
for (int i=0; i<2; ++i)
if(cur->nxt[i])
desinfo(cur->nxt[i]);
delete cur;
}
int main(void)
{
int T,n,m,i,s,val;
scanf("%d",&T);
for (int q=1; q<=T; ++q)
{
L=new info();
scanf("%d%d",&n,&m);
for (i=0; i<n; ++i)
{
scanf("%d",&val);
update(val);
}
printf("Case #%d:\n",q);
for (i=0; i<m; ++i)
{
scanf("%d",&s);
printf("%d\n",query(s));
}
//desinfo(L);
}
return 0;
}
