https://codeforces.com/contest/1446/problem/C
去年暑假多校补了两道稳定婚姻关系,今天把这题做成图论题自闭了两小时
看了牛逼网友十多分钟写完的代码,我真是草了感觉又要回绿重造经典再现了
直接考虑吧所有数字按位插入字典树,然后考虑dfs,如果字典树中某一棵子树中有两个点,那么由于这棵子树向上位都是相同的,那么这棵子树内部的点一定是两两匹配最小的
接下来我们考虑如何贪心得到最多的点
我们考虑如何计算字典树上没有个点的值,如果他左右两棵子树都有点,而且已经计算过了他们最多可以取多少可以使得只有一对互为异或最小,分别为l,r,那么这个点的答案就是max(l,r)+1,也就是要么左子树全选,右子树选一个点,这样右子树的那个点的异或对应最小值就是左子树的某个点了,而且异或值要跨过当前枚举点的这一位,也就是这一位为1
可以在字典树上写,也可以对a数组排序以后直接在数列上分治,分治一段区间在前已经枚举的i位完全相同,再考虑这一位
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=2e5+10;
int n,m,cnt,tot,cas,ans;
int a[maxl],b[maxl],num[maxl*32];
int ind[maxl*32],sz[maxl*32],tr[maxl*32][2];
bool vis[maxl],pr[maxl];
char s[maxl];
vector<int> e[maxl];
inline void prework()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
int u=0,c;
for(int j=30;j>=0;j--)
{
c=(a[i]>>j)&1;
if(!tr[u][c])
tr[u][c]=++tot;
u=tr[u][c];++num[u];
}
ind[u]=i;
}
}
inline int dfs(int u)
{
if(!tr[u][0] && !tr[u][1])
return 1;
int l=0,r=0;
if(tr[u][0])
l=dfs(tr[u][0]);
if(tr[u][1])
r=dfs(tr[u][1]);
if(!tr[u][1])
return l;
if(!tr[u][0])
return r;
return max(l,r)+1;
}
inline void mainwork()
{
ans=n-dfs(0);
}
inline void print()
{
printf("%d\n",ans);
}
int main()
{
int t=1;
//scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}