CF241B Friends
Link
先考虑求出第\(k\)大的\(a_i\operatorname{xor}a_j\),可以在建出Trie树之后高位贪心。
然后需要求出比这个数大的和。
在Trie树上额外维护\(c_{u,i}\)表示在\(u\)的子树内有多少个数的第\(i\)位为\(1\)。
在高位贪心的时候,如果当前位能够凑到的\(1\)的数量比\(k\)大,那么这一位的取值就是\(0\),此时我们利用额外维护的信息计算前\(k\)大中有多少个这一位为\(1\)。
#include<cstdio>
using i64=long long;
const int N=50007,M=30;
int tot=1,a[N],p[N];
struct node{int size,ch[2],c[M];}t[N*16];
int read(){int x;scanf("%d",&x);return x;}
void insert(int x)
{
for(int i=29,p=1,d;~i;--i)
{
d=x>>i&1,++t[p=t[p].ch[d]? t[p].ch[d]:t[p].ch[d]=++tot].size;
for(int j=0;j<30;++j) t[p].c[j]+=x>>j&1;
}
}
int main()
{
int n=read();i64 m=2ll*read(),ans=0,base=0;
for(int i=1;i<=n;++i) insert(a[i]=read()),p[i]=1;
for(int i=29;m&&~i;--i)
{
i64 s=0;
for(int j=1;j<=n;++j) s+=t[t[p[j]].ch[!(a[j]>>i&1)]].size;
if(s<=m)
{
for(int j=1,q,d;d=a[j]>>i&1,q=p[j],j<=n;p[j++]=t[q].ch[d])
if(q) for(int k=0;k<30;++k) ans+=1ll*(a[j]>>k&1? t[t[q].ch[!d]].size-t[t[q].ch[!d]].c[k]:t[t[q].ch[!d]].c[k])<<k;
m-=s;
}
else for(int j=1;j<=n;++j) p[j]=t[p[j]].ch[!(a[j]>>i&1)],base|=1<<i;
}
printf("%lld",(ans+m*base)/2%1000000007);
}