• CF241B Friends


    Link
    先考虑求出第(k)大的(a_ioperatorname{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);
    }
    
  • 相关阅读:
    直接插入排序
    直接选择排序
    冒泡排序
    归并排序
    进程调度
    进程与线程
    c语言struct和c++struct的区别
    二叉搜索树、AVL平衡二叉搜索树、红黑树、多路查找树

    6-11 先序输出叶结点
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12782365.html
Copyright © 2020-2023  润新知