Kanade's trio
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 767 Accepted Submission(s): 278
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
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 ,and the second line consists of n integers which means the array A[1..n]
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题意:让你在所给的序列找出有多少三元组i,j,k满足a[i]xor a[j] < a[j] xor a[k]解题思路:用两棵字典树维护,枚举a[j],j前面序列a[i]用一棵字典树维护,j后面的a[k]用一棵字典树维护,然后对于每个a[j],从他的最高位开始,在两棵树中分别找出这一位不同的位对应的数量,比如当前位是0,则需要在前缀树中找出这一位为0的个数x1, 在后缀树中找出这一位为1的个数x2,所以当前满足a[i] xor a[j] < a[j] xor a[k]的三元组数量是x1 * x2,然后接着往下找下去就行。#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 5e5 + 10; int n; int a[maxn]; ll ans[40][2];//表示每一层的结果 struct node{ int Next[2]; ll sum;//个数 node(){ memset(Next, -1, sizeof(Next)); sum = 0; } }; node Tree1[maxn<<2], Tree2[maxn<<2]; int res1, res2; int root1, root2; void cal(int root, int status, int d, int type, int op) { node *Treex, *Treey; if(type == 0) { Treex = Tree1; Treey = Tree2; } else { Treex = Tree2; Treey = Tree1; } if(type == 0)//前缀树 { if(status == 0) { int x1 = Treex[root].Next[0]; int x2 = Treey[root].Next[1]; if(x1 != -1 && x2 != -1) { ll sum1 = Treex[x1].sum; ll sum2 = Treey[x2].sum; ans[d][0] -= sum1 * sum2; ans[d][0] += (sum1 + op * 1) * (sum2); } } else { int x1 = Treex[root].Next[1]; int x2 = Treey[root].Next[0]; if(x1 != -1 && x2 != -1) { ll sum1 = Treex[x1].sum; ll sum2 = Treey[x2].sum; ans[d][1] -= sum1 * sum2; ans[d][1] += (sum1 + op * 1) * (sum2); } } } else { if(status == 0) { int x1 = Treex[root].Next[0]; int x2 = Treey[root].Next[1]; if(x1 != -1 && x2 != -1) { ll sum1 = Treex[x1].sum; ll sum2 = Treey[x2].sum; ans[d][1] -= sum1 * sum2; ans[d][1] += (sum1 + op * 1) * (sum2); } } else { int x1 = Treex[root].Next[1]; int x2 = Treey[root].Next[0]; if(x1 != -1 && x2 != -1) { ll sum1 = Treex[x1].sum; ll sum2 = Treey[x2].sum; ans[d][0] -= sum1 * sum2; ans[d][0] += (sum1 + op * 1) * (sum2); } } } } void Insert(int x, int type, node Tree[], int before) { int root; if(type == 0)//前缀树 { root = root1; } else root = root2; for(int i = 30; i >= 0; i--) { int num = (x>>i)&1; if(Tree[root].Next[num] == -1) { int res; if(type == 0) res = ++res1; else res = ++res2; Tree[root].Next[num] = res; } if(before) cal(root, num, i, type, 1); int id = Tree[root].Next[num]; Tree[id].sum++; root = id; } } void Delete(int x, int type, node Tree[], int before) { int root; if(type == 0)//前缀树 { root = root1; } else root = root2; for(int i = 30; i >= 0; i--) { int num = (x>>i)&1; if(before) cal(root, num, i, type, -1); int id = Tree[root].Next[num]; Tree[id].sum--; root = id; } } void init() { res1 = res2 = 0; memset(ans, 0, sizeof(ans)); int Maxn = (maxn<<2); for(int i = 0; i < Maxn; i++) { Tree1[i].Next[0] = Tree1[i].Next[1] = -1; Tree2[i].Next[0] = Tree2[i].Next[1] = -1; Tree1[i].sum = 0; Tree2[i].sum = 0; } } void initAns(int r1, int r2, int d) { if(d < 0 || r1 == -1 || r2 == -1) return; int x1 = Tree1[r1].Next[0]; int x2 = Tree2[r2].Next[1]; if(x1 != -1 && x2 != -1) { ans[d][0] += Tree1[x1].sum * Tree2[x2].sum; } initAns(x1, x1, d - 1); x1 = Tree1[r1].Next[1]; x2 = Tree2[r2].Next[0]; if(x1 != -1 && x2 != -1) { ans[d][1] += Tree1[x1].sum * Tree2[x2].sum; } initAns(x1, x1, d - 1); } ll solve(int x) { ll sum = 0; for(int i = 30; i >= 0; i--) { int num = (x>>i)&1; sum += ans[i][num]; } return sum; } int main() { int T; scanf("%d", &T); while(T--) { scanf("%d", &n); init(); root1 = ++res1; root2 = ++res2; for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); Insert(a[i], 0, Tree1, 0); Insert(a[i], 1, Tree2, 0); } initAns(root1, root2, 30); Delete(a[1], 1, Tree2, 1); for(int i = 2; i <= n; i++) { Delete(a[i], 0, Tree1, 1); } ll ssum = 0; for(int i = 2; i < n; i++) { Delete(a[i], 1, Tree2, 1); ssum += solve(a[i]); Insert(a[i], 0, Tree1, 1); } printf("%lld\n", ssum); } return 0; }