CF #673 (Div. 2)E. XOR Inverse(思维 、字典树)

本文介绍了解决Codeforces 1417 E题的解法,通过二进制高位策略,利用字典树计算每个相同高位的数内部的逆序对,优化异或操作以降低逆序对总数。核心思路是高位优先比较并利用异或1带来的正序对不变,逆序对减少的效果。
摘要由CSDN通过智能技术生成
https://codeforces.com/contest/1417/problem/E

题意:求一个最小的x,使x与数组a每一个元素异或后,逆序对数最小。

思路:二进制下,考虑数的高位对数值的大小影响更大,我们从最高位开始,如果这一位上异或1比异或0的逆序数对更小,那么最终答案的这一位就应该为1,否则为0。(最开始每一位上用树状数组求逆序对,然后T12了,看题解才知道需要用字典树,wao
//0 1序列异或1后,正序对数=之前的逆序数对,逆序对数=之前的正序数对

1、因为数的高位能直接接决定数值的大小,在当前位异或1并不能改变高位相同的这些数内部的逆序数对,所以我们处理时可以不用考虑整个数的大小,只需要看高位的逆序对数是否能通过异或1变得更小
2、同样的道理,当 当前位的前几位数确定且前几位不同时,改变当前位也不能改变这两个数的相对大小。所以我们只用计算每组相同高位的数内部的逆序数对和正序数对,看是否需要异或1。这就需要用到字典树了。

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<set>
#include<queue>
#include<vector>
using namespace std;
#define LL long long
#define uLL unsigned long long
#define PII pair<int,int>
#define mid ((l + r)>>1)
#define chl (root<<1)
#define chr (root<<1|1)
#define lowbit(x) ( x&(-x) )
const int manx = 5e6 + 10;
const int INF = 2e9;
const int mod = 1e4+7;

int n,tree[manx<<1][2],a,root,cou=1,siz[manx<<1];
LL dp[35][2];//dp[][0]dp[][1]分别代表每组相同高位的数 内部的逆序数对和 和 正序数和
void iinsert(int x)
{
    root=0;
    for(int i=30;i>=0;i--){
        int net=(x&(1<<i))?1:0;
        dp[i][net]+=siz[tree[root][net^1]];
        //因为按顺序插入字典树,所以:
        //当前位为1,正序数对+=高位相同时,当前位为0的数的个数
        //当前位为0,逆序数对+=高位相同时,当前位为1的数的个数
        if(!tree[root][net])
            tree[root][net]=cou++;
        root=tree[root][net];
        siz[root]++;
    }
}
int main()
{
    int ans=0;
    LL sum=0;
    scanf("%d",&n);
    memset(dp,0,sizeof dp);
    memset(siz,0,sizeof siz);
    for(int i=1;i<=n;i++){
        scanf("%d",&a);
        iinsert(a);
    }
    for(int i=30;i>=0;i--){
        if(dp[i][0]>dp[i][1]){//逆序对数和>正序对数和
            ans|=(1<<i);
            sum+=dp[i][1];
        }
        else sum+=dp[i][0];
    }
    printf("%lld %d\n",sum,ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值