DTOJ #3315. fullcombo

【题目描述】

给定一个长度为 $n$ 的序列 $a_i$,求第 $k$ 大的 $a_i ^ \land a_j (i \neq j)$ 值。

【输入格式】

第一行两个正整数 $n,k$。

第二行 $n$ 个正整数,第 $i$ 个为 $a_i$。

【输出格式】

一行一个数表示答案。

【样例】

样例输入
4 4
2 3 4 6

样例输出
6

【数据范围与提示】

除 $k$外所有数不超过 $5\times 10^4,k \leq n\times (n-1)$。

【题解】

看到两个数的异或值,不难想到 $Trie$。

由于第 $k$ 大并不方便逐位贪心,考虑二分。

二分 $check$ 时暴力从根节点开始跑,直接 $dfs$ 整颗 $Trie$ 即可。

效率 $O(2^{16}\times 16)$。

【代码】

#include<bits/stdc++.h>
inline long long read ( void )
{
    long long x=0;char ch;bool f=true;
    while ( !isdigit(ch=getchar()) ) if ( ch=='-' ) f=false;
    for ( x=ch^48;isdigit(ch=getchar()); ) x=(x<<1)+(x<<3)+(ch^48);
    return f ? x : -x ;
}
const int maxn=50000+10;
struct Trie
{
    int ch[maxn*100][17],val[maxn*100],tot;
    inline void insert ( int x )
    {
        int u=1;
        for ( int i=15;~i;i-- )
        {
            int k=(x>>i)&1;
            if ( !ch[u][k] ) ch[u][k]=++tot;
            u=ch[u][k];val[u]++;
        }
    }
    inline long long solve ( int u,int v,int x,int dep )
    {
        if ( !(~dep) ) return 1LL*val[u]*val[v];
        if ( !u or !v ) return 0;
        if ( (x>>dep)&1 )
        {
            if ( u==v ) return solve(ch[u][0],ch[v][1],x,dep-1);
            else return solve(ch[u][0],ch[v][1],x,dep-1)+solve(ch[u][1],ch[v][0],x,dep-1);
        }
        else return val[ch[u][0]]*val[ch[v][1]]+(u!=v)*val[ch[u][1]]*val[ch[v][0]]+solve(ch[u][0],ch[v][0],x,dep-1)+solve(ch[u][1],ch[v][1],x,dep-1);
    }
}T;
signed main()
{
    int n=read();long long k=read();T.tot++;
    while ( n-- ) T.insert(read());
    int L=0,R=(1<<16)-1;
    while ( L<R )
    {
        int mid=(L+R+1)>>1;
        if ( 2LL*T.solve(1,1,mid,15)>=k ) L=mid;
        else R=mid-1;
    }
    return !printf("%d\n",L);
}

猜你喜欢

转载自www.cnblogs.com/RenSheYu/p/11330248.html
今日推荐