1. 程式人生 > >HDU 6059 17多校3 Kanade's trio(字典樹)

HDU 6059 17多校3 Kanade's trio(字典樹)

要求 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.

1T20

1n5105

0A[i]<230

Input There is only one integer T on first line.

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]

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 的最高不相同位 kpip

ip=0 , kp=1 時,該最高不相同位之前的 ihigher=khigher 。則 jhigher 可以為任意數,均不對 i, k 更高位(指最高不相同位之前的高位,後同)的比較產生影響。而此時 jp 位必須為 0 才可保證不等式 (AiAj)<(AjAk) 成立。

ip=1,kp=0 時,jp 位必須為 1 ,更高位任意。

故利用數組 cnt[31][2] 統計每一位為 0 ,為 1 的有多少個(在前 K-1 個數中)。在字典樹插入第 k 個數時,同時統計最高不相同位,即對於每次插入的 p 位為 num[p]

(取值 0 或 1),在同父節點對應的 1-num[p] 為根子樹的所有節點均可作為 i 來尋找 j 以獲取對答案的貢獻。其中又僅要求 jpip (ip 值即 1-num[p]) 相同,故 jpcnt[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(字典樹)