题目链接

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

 
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

题意:输入一个数列a[1]~a[n] ,求有多少个三元组(i,j,k) 满足1<=i<j<k<=n  且  a[i]异或a[j] < a[j]异或a[k]?

思路:对于a[i]与a[k],对于二进制从高位向低位进行判断,如果30位(A[i]<2^30)到25位相同,那么a[j]的这些位不管值是多少不影响异或后 a[i] 与 a[k] 的大小关系,现在第24位不同,那么a[j]的这一位必须和a[i]相同,这样a[k]异或a[j]的值一定大于a[i]异或a[j] ,第23位到第0位不管a[j]取何值不会影响大小关系了。  有上述可以得出我们只需要判断a[i]和a[k]的二进制最高不相同位就行,那么可以用一个二进制的字典树存储这n个数。

从a[i]~a[n]将a[k]插入字典树中,每次插入时需要记录 当前节点有多少数(num表示)、当前节点对应的a[j]有多少(count表示),用cn[32][2]记录第i位为0和1时的a[j]的个数,所以每次到一个节点时用count+=cn[i][1-t],表示当前的位(0或1),这样可以保证j<k,但是没有保证i<j ;

接下来将cn[][]清空,从a[1]~a[n]的进行删除,对于a[i]删除,可以保证i<k ,那么可以用count-num*cn[i][t] 保证i<j ;

代码如下:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int N=5e5+;
int a[N],p[],cn[][];
struct node
{
node *son[];
int count;
int num;
node() { count=; num=; son[]=son[]=NULL; }
};
node *root; void add(int x,int v)
{
node * now=root;
for(int i=;i>=;i--)
{
int t=(!!(p[i]&x));
if(now->son[t]==NULL) now->son[t]=new node();
now=now->son[t];
now->num+=v;
cn[i][t]++;
now->count+=v*cn[i][-t];///当前点对应的j的个数;
}
} LL cal(int x)
{
node * now=root;
LL sum=;
for(int i=;i>=;i--)
{
int t=(!!(p[i]&x));
node* bro=now->son[-t];
if(bro)
sum+=bro->count - ((LL)bro->num*(LL)cn[i][t]);
now=now->son[t];
if(!now) break;
}
return sum;
} int main()
{
///cout << "Hello world!" << endl;
int T; cin>>T;
p[]=;
for(int i=;i<;i++) p[i]=p[i-]<<;
while(T--)
{
int n; scanf("%d",&n);
for(int i=;i<=n;i++) scanf("%d",&a[i]);
root=new node();
memset(cn,,sizeof(cn));
for(int i=;i<=n;i++) add(a[i],);
memset(cn,,sizeof(cn));
LL ans=;
for(int i=;i<n;i++){
add(a[i],-);
ans+=cal(a[i]);
}
printf("%lld\n",ans);
}
return ;
}

最新文章

  1. 利用Python进行数据分析(13) pandas基础: 数据重塑/轴向旋转
  2. 【Cocos2d-x 3.X 资源及脚本解密】
  3. Html - Bootstrap 头部
  4. 使用TortoiseGit将代码上传到bitbucket
  5. NSString NSMutableString copy mutableCopy retain weak strong整合
  6. SQL Server存储过程同时返回分页结果集和总数
  7. JPA 系列教程6-单向多对多
  8. gcd timer
  9. Java NIO学习笔记一 Java NIO概述
  10. Celery 源码解析四: 定时任务的实现
  11. [转载] Java NIO与IO
  12. 搭建内网的NTP时间服务器
  13. HTTP协议7之Cookie--转
  14. soapUI启动报错:The JVM could not be started. The maximum heap size (-Xmx) might be too large or an antivirus or firewall tool could block the execution.
  15. Python动态语言的特性
  16. 孙子兵法的计是最早的SWOT分析,《孙子兵法》首先不是战法,而是不战之法。首先不是战胜之法,而是不败之法
  17. js求渐升数的第100位
  18. C# 获取当前路径方法整理
  19. StringEscapeUtils对字符串进行各种转义与反转义
  20. Python笔记(四):异常处理机制与 open()

热门文章

  1. Linux 特殊用户权限 suid,sgid, sticky
  2. python 标准库 -- re
  3. C#中==运算符
  4. Spingmvc项目注册登录图片验证码(比较灵活的验证码)
  5. 关于MATLAB处理大数据坐标文件2017528
  6. BigDecimal四舍五入使用总结
  7. top命令总结
  8. jQuery怎样判断按钮是否被选中
  9. 如何让局域网内的其他电脑访问本机的mysql
  10. 屏幕适配/autoLayout autoresizingMask