zoukankan      html  css  js  c++  java
  • 【CF1416C】XOR Inverse

    题目描述

    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_noplus 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;
    }
    
  • 相关阅读:
    mvc 4 ActionFilterAttribute 特性,进行权限验证
    asp.net 将word文档进行编辑并导出一个新的word
    怎样才能最快速的找到破解软件?
    C#动态执行字符串(动态创建代码)
    使用Memcached提高.NET应用程序的性能
    ASP.NET 创建网站地图
    TFS2010安装办法及序列号
    在将 varchar 值 '1,2,3,4,5,6,7,8' 转换成数据类型 int 时失败。
    Js获取当前日期时间及其它操作
    截取Excel字符串的部分字符
  • 原文地址:https://www.cnblogs.com/lrj124/p/14044963.html
Copyright © 2011-2022 走看看