Kanade's trio
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 1067 Accepted Submission(s): 392
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
Source
Recommend
liuyiding
http://blog.csdn.net/DorMOUSENone/article/details/76570172?locationNum=2&fps=1 看的是这位大佬的博客学的。
题意:给一个数列,找出多少个这样的有序三元组<i,j,k>满足a[i] xor a[j] < a[j] xor a[k]
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 500000 + 10;
const int Node_max = N * 31;
int T, n, num[30], a[N], cnt[31][2];
long long ext = 0, ans;
struct Node{
int nxt[2];
int cnt, ext;
} Trie[Node_max];
int Tsize;
void calc(int tmp, long long c) {
//当前节点往下走有多少个字符串,从中间选两个
ans += Trie[tmp].cnt * 1ll * (Trie[tmp].cnt - 1) / 2;
//c代表的是这一位上,和初始字符不用的字符个数
ext += (c-Trie[tmp].cnt) * 1ll * Trie[tmp].cnt - Trie[tmp].ext;
}
void Trie_insert(int idx){
int tmp = 0;
for(int i=0;i<30;i++){
if(!Trie[tmp].nxt[ num[i] ]) {
Trie[tmp].nxt[ num[i] ] = ++Tsize;
}
//如果另一条路能走
if(Trie[tmp].nxt[ 1-num[i] ]) {
calc(Trie[tmp].nxt[ 1-num[i] ], cnt[i][ 1-num[i] ]);
}
tmp = Trie[tmp].nxt[ num[i] ];
Trie[tmp].cnt++;
//
Trie[tmp].ext += cnt[i][num[i]] - Trie[tmp].cnt;
}
return;
}
int main()
{
scanf("%d", &T);
while(T-- && scanf("%d", &n)!=EOF)
{
memset(Trie, 0, Tsize * 16 + 16);
memset(cnt, 0, sizeof(cnt));
Tsize = 0;
ans = 0;
ext = 0;
for(int i=1, tmp;i<=n;i++)
{
scanf("%d", &a[i]);
tmp = a[i];
for(int j=29;j>=0;j--) {
num[j] = tmp%2;
cnt[j][tmp%2]++;//记录每一位为0或者为1的有多少个
tmp /= 2;
}
Trie_insert(i);
}
printf("%lld\n", ans + ext);
}
}