题意:
给出一个长度为 n n n的数组 a a a ,求一个最小的 x x x,使得 b [ i ] = a [ i ] ⨁ x b[i]=a[i] \bigoplus x b[i]=a[i]⨁x ,且数组 b b b的逆序对数量最少。
题解:
比较两个数的大小,可以将其变为二进制,从高位往低位依次比较,直至遇到该位上的数不同。
那么我们可以从前往后依次向字典树中插入每一个元素,插入数的过程中,从高位到低位依次考虑。
假设当前是第 i i i 位,如果插入的数在 i i i 位为 0 0 0 , 那么该位贡献的逆序对数为 t r e e [ r o o t ] [ 1 ] tree[root][1] tree[root][1] 的大小,反之如果为 1 1 1,
该位贡献的正序对数为 t r e e [ i ] [ 0 ] tree[i][0] tree[i][0] 的大小。
另 d p [ i ] [ 0 ] dp[i][0] dp[i][0] 表示二进制第 i i i 位正序对的个数, d p [ i ] [ 1 ] dp[i][1] dp[i][1] 表示二进制第 i i i 位逆序对的个数。
那么从高到低依次考虑 x x x的每一位,如果 d p [ i ] [ 0 ] < d p [ i ] [ 1 ] dp[i][0]<dp[i][1] dp[i][0]<dp[i][1] ,说明该位为 1 1 1 可以使得逆序对的数量更少,反之则为 0 0 0。
代码:
#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int MAXN=3e5+5;
const int inf=0x3f3f3f3f;
int tree[MAXN * 20][2];
ll num[MAXN * 20], dp[50][2];
int a[MAXN];
int cnt = 0;
void insert(int x)
{
int root = 0;
for (int i = 30; i >= 0;i--){
int id = ((x >> i) & 1);
if(!tree[root][id])
tree[root][id] = ++cnt;
if(id==0&&tree[root][1])
dp[i][1] += num[tree[root][1]];
else if(id==1&&tree[root][0]){
dp[i][0] += num[tree[root][0]];
}
root = tree[root][id];
num[root]++;
}
}
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n;i++){
cin >> a[i];
}
for (int i = 1; i <= n;i++){
insert(a[i]);
}
ll sum = 0, ans = 0;
for (int i = 30; i >=0;i--){
if(dp[i][0]<dp[i][1]){
sum += dp[i][0];
ans += (1 << i);
}
else{
sum += dp[i][1];
}
}
cout << sum << " " << ans << endl;
}