Kanade's trio
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 711 Accepted Submission(s): 255
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
题意:
给你n个数,选择三个数按顺序,前2个数的异或小于后两个数的异或值,问你能找到多少组满足提议要求的数对。
题解:
感觉01异或题大部分都需要字典树搞搞,毕竟复杂度在哪摆着的,本题可以这样讨论,无非就两种情况:
(1)假如i和j的第p位是0,则k的第p为要是1,并且p是j和k的最高不相同位,此时满足要求,计入贡献。
(2)假如i和k的最高不相同位p中,i和j在第p位上数值相同,则也满足要求,并计入贡献。
第一种很好处理,定义个一个二维数组cnt[i][j]:表示第i位为j的数的个数。则第一种的贡献值便是cnt[i][1-j]*(cnt[i][1-j]-1)/2,这里很好弄懂,就不过多解释了。
第二种情况就比较麻烦了,因为需要考虑顺序(不是说第一种不用考虑,第一种按照组合数的定义其实就是把顺序考虑在内的),然而第二种就很麻烦了,因为此时要找的i和j不在一个子树中,并且j必须要在i之后,看了大神的思路,可以这样搞,考虑将要加入的数当做i,则前边所有能和i构成i/j关系的数都被当做不合法情况,故字典树存一个ext值表示该数之前所有能与该数组成i/j关系的数的个数,最后在统计贡献时减掉就好了。
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<math.h>
#include<time.h>
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
typedef long long ll;
#define inf 2147483647
#define mod 1000000007
#define maxn 5000005
#define lowbit(x) (x&-x)
#define eps 1e-10
int num[32],cnt[32][2],size;
ll ans,ext;
struct node
{
int next[2];
int cnt,ext;
}Trie[maxn];
void work(int tmp,ll c)
{
ans+=1ll*(Trie[tmp].cnt-1)*Trie[tmp].cnt/2;
ext+=1ll*(c-Trie[tmp].cnt)*Trie[tmp].cnt-Trie[tmp].ext;
}
void insert()
{
int i,tmp=0;
for(i=0;i<=29;i++)
{
if(!Trie[tmp].next[num[i]])
Trie[tmp].next[num[i]]=++size;
if(Trie[tmp].next[1-num[i]])
work(Trie[tmp].next[1-num[i]],cnt[i][1-num[i]]);
tmp=Trie[tmp].next[num[i]];Trie[tmp].cnt++;
Trie[tmp].ext+=cnt[i][num[i]]-Trie[tmp].cnt;
}
}
int main(void)
{
int T,i,j,n,x;
scanf("%d",&T);
while(T--)
{
ans=ext=0;size=0;
memset(cnt,0,sizeof(cnt));
memset(Trie,0,sizeof(Trie));
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&x);
for(j=29;j>=0;j--)
{
num[j]=x%2;
cnt[j][x%2]++;
x/=2;
}
insert();
}
printf("%lld\n",ans+ext);
}
return 0;
}