【CF1416C XOR】Inverse - 01-Trie

題目描述

You are given an array aa consisting of \(n\) non-negative integers. You have to choose a non-negative integer \(x\) and form a new array \(b\) of size \(n\) according to the following rule: for all \(i\) from \(1\) to \(n\) , \(b_i = a_i \oplus x\)(\(\oplus\) denotes the operation bitwise XOR).
An inversion in the \(b\) array is a pair of integers \(i\) and \(j\) such that \(1 \le i < j \le n\) and \(b_i > b_j\).
You should choose \(x\) in such a way that the number of inversions in \(b\) is minimized. If there are several options for \(x\) — output the smallest one.

題目大意

給定長度爲 \(n\) 的數列 \(\{a_n\}\),請求出最小的整數 \(x\) 使 \(\{a_n\oplus x\}\) 的逆序對數最少

題解

可以發現若 \(x\) 的某一位上是 1,就相當於交換了那一位那層的 Trie 的所有左右子樹
再考慮哪些位上要交換,可以發現 Trie 樹葉子上,一個點在另一個點左邊,那右邊這個點一定小於左邊的點
那可以將每一個數依次插入 Trie 上,Trie 上的結點這個子樹葉子的結點的編號
可以發現葉子節點編號的逆序對就是原數組的逆序對,因爲原數組若一個數後面有比它小的數,小的數會比它後加入並且插入 Trie 的葉子後在它的前面
因爲兩顆子樹內部數的順序是不影響兩棵之間的逆序對個數的,所以就可以計算每一層所有子樹反轉或不反轉的逆序對個數了

#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn = 3e5 + 10;
const int N = 30;
vector<int> num[maxn*N];
int n,tot,ch[maxn*N][2];
long long cnt[N+1][2];
inline void insert(int x,int v) {
	int u = 0;
	for (int i = N;~i;i--) {
		int bit = (x>>i)&1;
		num[u].push_back(v);
		if (!ch[u][bit]) ch[u][bit] = ++tot;
		u = ch[u][bit];
	}
	num[u].push_back(v);
}
inline void solve(int u,int i) {
	if (i < 0) return;
	if (ch[u][0]) solve(ch[u][0],i-1);
	if (ch[u][1]) solve(ch[u][1],i-1);
	if (!ch[u][0] || !ch[u][1]) return;
	long long res = 0;
	for (size_t j = 0;j < num[ch[u][1]].size();j++)
		res += num[ch[u][0]].end()-lower_bound(num[ch[u][0]].begin(),num[ch[u][0]].end(),num[ch[u][1]][j]);
	cnt[i][0] += res;
	cnt[i][1] += 1ll*num[ch[u][0]].size()*num[ch[u][1]].size()-res;
}
int main() {
	scanf("%d",&n);
	for (int i = 1,x;i <= n;i++) { scanf("%d",&x); insert(x,i); }
	solve(0,N);
	long long ans = 0;
	int res = 0;
	for (int i = 0;i <= N;i++)
		if (cnt[i][0] <= cnt[i][1]) ans += cnt[i][0];
		else { ans += cnt[i][1]; res |= 1<<i; }
	printf("%lld %d",ans,res);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章