HDU 6059 17多校3 Kanade's trio(字典樹)
阿新 • • 發佈:2017-08-05
要求 tro none sat details num cst void stream Problem Description
Give you an array A[1..n],you need to calculate how many tuples (i,j,k) satisfy that (i<j<k) and ((A[i] xor A[j])<(A[j] xor A[k]))
There are T test cases.
1≤T≤20
1≤∑n≤5∗105
0≤A[i]<230
For each test case , the first line consists of one integer n ,and the second line consists of n integers which means the array A[1..n]
There are T test cases.
1≤T≤20
1≤∑n≤5∗105
0≤A[i]<230
Input There is only one integer T on first line.
For each test case , the first line consists of one integer n
Output For each test case , output an integer , which means the answer.
Sample Input 1 5 1 2 3 4 5
Sample Output 6 啟發博客:http://blog.csdn.net/dormousenone/article/details/76570172 摘:
利用字典樹維護前 k-1 個數。當前處理第 k 個數。
顯然對於 k 與 i 的最高不相同位 kp 與 ip :
當 ip=0 , kp=1 時,該最高不相同位之前的 ihigher=khigher 。則 jhigher 可以為任意數,均不對 i, k 更高位(指最高不相同位之前的高位,後同)的比較產生影響。而此時 jp 位必須為 0 才可保證不等式 (Ai⊕Aj)<(Aj⊕Ak) 成立。
當 ip=1,kp=0 時,jp 位必須為 1 ,更高位任意。
故利用數組 cnt[31][2]
統計每一位為 0 ,為 1 的有多少個(在前 K-1 個數中)。在字典樹插入第 k 個數時,同時統計最高不相同位,即對於每次插入的 p 位為 num[p]
(取值 0 或 1),在同父節點對應的 1-num[p]
為根子樹的所有節點均可作為 i 來尋找 j 以獲取對答案的貢獻。其中又僅要求 jp 與 ip (ip 值即 1-num[p]
) 相同,故 jp 有 cnt[p][ 1-num[p] ]
種取值方案。
但是,同時需要註意 i 與 j 有在 A 數組的先後關系 (i<j) 需要保證。故在字典樹中額外維護一個 Ext
點,記錄將每次新加入的點與多少原有點可構成 i, j
關系。在後續計算貢獻時去掉。
其余詳見代碼註釋。
1 #include <iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<queue> 5 #include<map> 6 #include<vector> 7 #include<cmath> 8 #include<cstring> 9 using namespace std; 10 long long ans1,ans2; 11 int num[35];//每一個數字的二進制轉化 12 int cnt[35][2];//cnt[i][j]記錄全部插入數字第i位為0、1分別的數字 13 14 struct trie 15 { 16 trie* next[2]; 17 int cnt,ext; 18 trie() 19 { 20 next[0]=NULL; 21 next[1]=NULL; 22 cnt=0;//擁有當前前綴的數字個數 23 ext=0;// 24 } 25 }; 26 27 void calc(trie* tmp,long long c) 28 { 29 ans1+=tmp->cnt*(tmp->cnt-1)/2; 30 ans2+=(c-tmp->cnt)*tmp->cnt-tmp->ext; 31 } 32 33 void insert(trie* r) 34 { 35 int i; 36 for(i=1;i<=30;i++) 37 { 38 if(r->next[num[i]]==NULL) 39 r->next[num[i]]= new trie; 40 if(r->next[1-num[i]]!=NULL) 41 calc(r->next[1-num[i]],cnt[i][1-num[i]]); 42 r=r->next[num[i]]; 43 r->cnt++; 44 r->ext+=cnt[i][num[i]]-r->cnt; 45 //每個點存下同位同數不同父親節點的數字個數且序號比本身小的 46 } 47 return ; 48 } 49 50 int main() 51 { 52 int T,n,tmp; 53 scanf("%d",&T); 54 while(T--) 55 { 56 scanf("%d",&n); 57 trie root; 58 ans1=0;//i,j選自同父親節點 59 ans2=0;//i選自同父親節點,j選擇同位不同數不同父親節點 60 memset(cnt,0,sizeof(cnt)); 61 while(n--) 62 { 63 scanf("%d",&tmp); 64 for(int i=30;i>=1;i--)//這樣可以保證不同大小的數字前綴都為0 65 { 66 num[i]=tmp%2; 67 cnt[i][num[i]]++; 68 tmp/=2; 69 } 70 insert(&root); 71 } 72 printf("%lld\n",ans1+ans2); 73 } 74 return 0; 75 }
HDU 6059 17多校3 Kanade's trio(字典樹)