0
点赞
收藏
分享

微信扫一扫

Daimayuan Online Judge #497. XOR Inverse

脱下愤怒的小裤衩 2022-03-14 阅读 141
c++算法

题目链接:XOR Inverse - 题目 - Daimayuan Online Judge

题解链接:【算法Camp】【每日一题】Namomo Spring Camp 2022 Div1 第11天题解(位运算、逆序对)_哔哩哔哩_bilibili

 

思路:

  1. 两个数谁大谁小,取决于从高到低第一个不一样的位,只有x这一位的值会对两者大小产生影响。
  2. 第一个不一样的位取到0的时候,统计前面的这一位为1的数字数量,记入逆序对数量的贡献。
  3. 高低位的问题可以用trie树来维护。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define FOR(i, a, b) for (int i = (a); i <= (b); i++)
const int N = 3e5+5;
int n, a[N], sum, ans;
int ch[N*31][2],sz[N*30],f[31][2], tot; //f[i][0]表示x第i位取0的时候的逆序对数,f[i][1]表示x第i位取1的时候的逆序对数
//注意ch和sz的大小要开够,总共N个数字,每个数字31位,最多开31*N个点的位置

inline void add(int x){
	int p=0;
	for(int i=30; i>=0; i--){
		int t=(x>>i)&1; //第i位数字
		if(!ch[p][t]) ch[p][t]=++tot; //如果没有这个点,就创建一个
		f[i][t] += sz[ch[p][t^1]]; //加上和当前数字同层的另一种数字的数量(当前数字t异或t变成了0,另外一种数字异或t变成1)
		p=ch[p][t]; sz[p]++; //移动到对应位置,对应的sz增加
	}
}
signed main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	cin>>n; FOR(i,1,n) cin>>a[i], add(a[i]);
	FOR(i,0,30){
		if(f[i][0]>f[i][1]) ans+=(1<<i); //对应位置取1更优
		sum += min(f[i][0],f[i][1]);
	}
	cout<<sum<<' '<<ans<<'\n';
}
举报

相关推荐

0 条评论