题意:
解法:
n个点,每个点向外连一条边,因此只有n条边,
那么图中可能存在若干连通块.
容易证明,每个连通块内部是不存在环的,
因为有环就和异或值最小冲突了(不详细证明了).
那么问题可以变为删除最少的数,使得图中只有一个连通块.
将所有数插入01Trie,
考虑什么情况下才可能会有多个连通块,
对于节点node,如果sz[a[node][0]]>=2且sz[a[node][1]]>=2,
那么两颗子树中的节点一定只和自己子树中的点匹配,
因为这样匹配异或和才最小,
但是两颗子树都自匹配的话,就会出现两个连通块,
因此我们要将某一个子树的节点删到只有1,
显然删sz[]最小的子树,代价为sz[]-1.
在01Trie树上跑一下树形dp求最小代价即可.
code:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxm=2e5+5;
struct Trie{
int a[maxm*32][2],tot;
int sz[maxm*32];
int d[maxm*32];//d[i]表示令以点i为根的子树满足条件至少需要删除多少个数.
int rt;
void add(int &node,int x,int k){
if(!node)node=++tot;
if(k==-1){
sz[node]++;return ;
}
int v=(x>>k&1);
add(a[node][v],x,k-1);
}
void dfs(int node,int k){
if(k==-1)return ;
if(a[node][0])dfs(a[node][0],k-1);
if(a[node][1])dfs(a[node][1],k-1);
d[node]=d[a[node][0]]+d[a[node][1]];
sz[node]=sz[a[node][0]]+sz[a[node][1]];
if(sz[a[node][0]]>=2&&sz[a[node][1]]>=2){//如果两边的sz都>1,那么子树内会自己匹配.
//贪心地将少的那一边减为1
int mi=min(sz[a[node][0]],sz[a[node][1]])-1;
d[node]+=mi;
sz[node]-=mi;
}
}
}T;
int n;
inline void solve(){
cin>>n;
for(int i=1;i<=n;i++){
int x;cin>>x;
T.add(T.rt,x,30);
}
T.dfs(T.rt,30);
int ans=T.d[T.rt];
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);
solve();
return 0;
}