Marsrayd
2021-12-26 17:16:31
给定你一个序列
简单 dp 能力。
求最小删除数十分困难,不如转过来求最大保留。
先将每个数字插入
因为异或值最小的两个数才会连边。
所以没删除前一定是
要让他们变为一棵树,就就必须删除一些点。
记以
其实按上图中连边,我们已经求出了:
然后我们继续递归处理。
开始处理
为什么呢?因为
所以为了让这棵子树内的树与另一棵子树上的树连边,只能令这棵子树只留下它一个数。
于是
记
列完转移发现甚至不需要记录
#include<bits/stdc++.h>
#define IN inline
const int N=3000010;
IN int read()
{
int x=0; char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x;
}
int idx;
struct Trie_Tree{int son[2];}tr[N];
inline void insert(int x)
{
int p=0;
for(int i=30;i>=0;i--)
{
int tmp=(x>>i)&1;
if(!tr[p].son[tmp]) tr[p].son[tmp]=++idx;
p=tr[p].son[tmp];
}
}
long long dp(int p)
{
if(!tr[p].son[0]&&!tr[p].son[1]) return 1;
if(!tr[p].son[0]&&tr[p].son[1]) return dp(tr[p].son[1]);
if(tr[p].son[0]&&!tr[p].son[1]) return dp(tr[p].son[0]);
return std::max(dp(tr[p].son[0]),dp(tr[p].son[1]))+1;
}
int main()
{
int n=read();
for(int i=1;i<=n;i++) insert(read());
return !printf("%lld",n-dp(0));
}
欢迎提问or提出我的问题,会改的。