1.题意

给你n个数,n个数的权值,然后它们连边的规则是每个数连向它们异或最小的边.然后问你最少删掉多少个数,才能使得它们构成一棵树?


2.思路

对于位运算,我们应该从高位向低位进行.既然是从高位向低位进行,那么思考一下,假如那个高位有两个1,两个0,它们会如何连边.必定是1与1相连,0与0相连,所以考虑每一位,假如我选取1的话,这位为0的点就只能保留一个,假如我这位选0的话,这位的1的点就只能保留一个.所以直接dfs在字典树上跑就好了...maybe?


3.代码

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+50;
int son[2][N*100],id;
int cnt[N*100];
void insert(int x)
{
    int p=0;
    for(int i=29;i;i--)
    {
        int pos=(x>>i&1);//这位是1还是0.
        int &s=son[pos][p];
        if(!s)  s=++id;
        p=s;
    }cnt[p]++;
}

int query(int u)//查询当前层最多保留的值的数量.
{
    int l=son[0][u];int r=son[1][u];
    if(l&&r)    return cnt[u]+max(query(l),query(r))+1;
    else if(l)  return cnt[u]+query(l);
    else if(r)  return cnt[u]+query(r);
    else return cnt[u];
}

int main()
{
    int n;scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        insert(x);
    }
    int ans=n-query(0);
    cout<<ans<<endl;
    return 0;
}