码迷,mamicode.com
首页 > 其他好文 > 详细

51nod 1150 Logarithm

时间:2016-08-18 00:51:43      阅读:253      评论:0      收藏:0      [点我收藏+]

标签:

题目来源: Ural 1318
给出n个互不相等的整数A[0] - A[n-1],选A[i]同A[j]进行异或运算(结果都 > 0无符号),对结果取lg(以10为底)并取整后记为L[i,j],求n个数之间两两运算得到的L[i,j]之和。
 
技术分享
 
例如:1 10 30,1 xor 10 = 11,10 xor 30 = 20,1 xor 30 = 31。Sum = Lg(11) * 2 + Lg(20) * 2 + Lg(30) * 2 = (1 + 1 + 1) * 2 = 6(取整)。
由于i j同j i算作2个不同的,因此最终结果要 * 2。
Input
第1行:1个数N,表示整数的数量。(2 <= N <= 50000)
第2 - N + 1行:每行个1数A[i](1 <= A[i] <= 10^18)
Output
输出两两异或后取Lg(以10为底)并取整后的和。

首先建出二进制trie,然后由数据范围知log10(A[i] xor A[j])在0到19,可以枚举每个数和log10的每个取值在trie上查询出现次数
#include<cstdio>
typedef long long i64;
i64 _(){
    i64 x=0;
    int c=getchar();
    while(c<48)c=getchar();
    while(c>47)x=x*10+c-48,c=getchar();
    return x;
}
const int N=50007*65;
int n;
i64 a[50007];
int ch[N][2],sz[N],ptr=1;
i64 ts[20],p10[20];
void ins(i64 x){
    int w=1;
    for(int i=62;~i;i--){
        int d=x>>i&1;
        if(!ch[w][d])ch[w][d]=++ptr;
        w=ch[w][d];
        ++sz[w];
    }
}
int find(i64 x,i64 y){
    int s=0,w=1;
    for(int i=62;~i;i--){
        int d1=x>>i&1,d2=y>>i&1;
        if(d2)s+=sz[ch[w][d1^d2^1]];
        w=ch[w][d1^d2];
    }
    return s;
}
int main(){
    n=_();
    for(int i=0;i<n;i++){
        a[i]=_();
        ins(a[i]);
    }
    p10[0]=1;
    for(int i=1;i<=18;i++)p10[i]=p10[i-1]*10;
    for(int i=0;i<n;i++){
        for(int j=1;j<=18;j++)ts[j]+=find(a[i],p10[j]);
    }
    ts[19]=1ll*n*n-ts[18];
    for(int i=18;i>1;i--)ts[i]-=ts[i-1];
    ts[1]-=n;
    i64 ans=0;
    for(int i=2;i<=19;i++)ans+=(i-1)*ts[i];
    printf("%lld",ans);
    return 0;
}

 

 

51nod 1150 Logarithm

标签:

原文地址:http://www.cnblogs.com/ccz181078/p/5782369.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!