trie树 + 树形dp

4869. 异或值 - AcWing题库

建出trie之后

考虑从根节点往下贪心考虑(高位到低位)

考虑节点要是分叉的情况我们序列中必然有数该位上为1

这样我们需要考虑往左往右走才是更优的

要是我们往左走了 就相当于可以不考虑右边的子树了 因为他们那边连高位的‘1’都没有显然不可能是最大值

要是不分叉我们就直接走就是了

然后考虑dp[u]:表示节点u子树包括的数异或后(ans)的最小值是什么

转移自然就只有三种 分叉一种 不分叉两种

分叉的话显然是左右两边的最小值+现在该位必为‘1’ dp[u]=min(dp[l],dp[r])+1<<(该位)

不分叉直接dp[u]=dp[]即可

题目让我们找到一个X ,使得X异或ai的最大值最小,并求出这个最小可能值。

所以我们其实不用求X,我们在trie上dp,直接求得最终的这个最小可能值。

如果在trie上一个节点往下有分叉,那么我们序列中必然有数该位上为1和0,那么任何X异或后,最终值的该位上必为1,所以要使最终值最小,此时最终值应为 min(left,right) + (1<<该位);


#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
const int N = 3e6 + 100;
int tr[N][2], idx;
int n;
int dp[N];

void insert(int x) {
    int p = 0;
    for(int i = 30; i >= 0; i--) {
        int u = x >> i & 1;
        if(!tr[p][u]) tr[p][u] = ++idx;
        p = tr[p][u];
    }
}

void dfs(int u, int dep) {
    int l = tr[u][0], r = tr[u][1];
    if(l) dfs(l, dep - 1);
    if(r) dfs(r, dep - 1);

    if(l && r) dp[u] = min(dp[l], dp[r]) + (1 << dep);
    else if(l) dp[u] += dp[l];
    else if(r) dp[u] += dp[r];
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n;
    for(int i = 1; i <= n; i++) {
        int x;
        cin >> x;
        insert(x);
    }    

    dfs(0, 30);

    cout << dp[0] << endl;

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值