[51nod1150] Logarithm
2016-12-16 22:21
183 查看
题目大意
给定一个n个正整数的数组A[],求∑i≠jlg(A[i]xorA[j])n≤50000 1≤A[i]≤1018
分析
首先每个数不会很大,那么任意一个异或起来的数的lg值不会超过18然后可以考虑lg的值,假设是x,然后可以确定一个区间[10x,10x+1),如果异或值在这个区间内,它对答案的贡献就是x。
然后就是求多少个异或值在一个区间内,做法就是套路:可以先把所有数放进二进制trie里,然后枚举每个数,在trie上跑即可。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=50005,M=N*62; typedef unsigned long long LL; int n,tot,son[M][2],cnt[M]; LL Ans ,A ,s,p ; char c; LL read() { for (c=getchar();c<'0' || c>'9';c=getchar()); LL x=c-48; for (c=getchar();c>='0' && c<='9';c=getchar()) x=x*10+c-48; return x; } void insert(LL x,int y,int z) { if (y<0) return; int w=((x & p[y])>0); if (!son[z][w]) son[z][w]=++tot; cnt[son[z][w]]++; insert(x,y-1,son[z][w]); } int get(LL x,LL k,int y,int z) { if (y<0 || !z) return cnt[z]; int w=((x & p[y])>0); if ((k & p[y])==0) return get(x,k,y-1,son[z][w])+cnt[son[z][1-w]]; return get(x,k,y-1,son[z][1-w]); } int main() { scanf("%d",&n); p[0]=1; for (int i=1;i<=62;i++) p[i]=p[i-1]*2; tot=1; for (int i=0;i<n;i++) { A[i]=read(); insert(A[i],61,1); } for (LL i=1,t=10;t<=1e18;i++,t*=10) { Ans[i]=(LL)n*(n-1); for (int j=0;j<n;j++) Ans[i]-=get(A[j],t,61,1); if (i>0) s+=(i-1)*(Ans[i]-Ans[i-1]); if (t==1e19) break; } s+=((LL)n*(n-1)-Ans[18])*18; printf("%lld\n",s); return 0; }
相关文章推荐
- 烂泥:VMWare Workation双网卡配置IP地址
- COM(3)
- hdr_beg(host) hdr_reg(host) hdr_dom(host)
- Linux根文件系统分析之init和busybox
- 学习TensorFlow,保存学习到的网络结构参数并调用
- mysql常见少用方法
- 烂泥:VMWare Workation双网卡配置IP地址
- Maven搭建SpringMVC+Spring+Mybatis项目详解
- spring scope prototype与singleton区别
- Linux下的C语言编程——买鸡问题
- 序
- LCQCL
- Struts2文件上传
- C#套接字学习总结
- redis一:安装以及常见操作
- boneCP原理研究
- Qt入门-QPushButton
- mysql命令行下的安装以及建表、插入、查看数据
- 创建CSDN的第一篇博客
- 回调函数