题意:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210428171547511.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDE3ODczNg==,size_16,color_FFFFFF,t_70)
解法:
因为是异或,显然往二进制考虑.
考虑x的二进制从高位起第i位为1会有什么影响:
对于[1,i-1]相同,第i位不同的数,
这样的数是通过第i位的0,1进行比较的,
如果x为1,会导致这样的数形成的顺、逆序对数量变换.
那么我们统计每个位上正序对和逆序对的数量,
如果逆序对>顺序对,那么x=1,因为交换会使得逆序对数量变少.
如何统计每个位上顺序对和逆序对数量呢,
01用字典树做:
开sz[node]表示node下有多少个数,
rev[node]表示当前节点决定的逆序对数量,
sum[node]表示当前节点决定的顺序对数量.
如何维护rev[node]和sum[node]:
每次插入一个数,如果当前位为0,
那么rev[node]+=sz[a[node][1]].
如果当前位为1,那么sum[node]+=sz[a[node][0]].
设s[i]为第i位上的顺序对数量和,
r[i]为第i位上的逆序对数量和,
s[]和r[]可以通过dfs字典树得到.
对于每一位i,如果r[i]>s[i],那么x|=(1<<i),即交换,
否则不交换.
code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxm=3e5+5;
int a[maxm];
int r[maxm];
int s[maxm];
int n;
int cal(int x){
return x*(x-1)/2;
}
struct Trie{
int a[maxm*30][2],tot=1;
int sz[maxm*30];
int sum[maxm*30];
int rev[maxm*30];
void add(int x,int i,int node){
if(i==-1){
sz[node]++;
return ;
}
int v=(x>>i&1);
if(v==0)rev[node]+=sz[a[node][1]];
else sum[node]+=sz[a[node][0]];
if(!a[node][v])a[node][v]=++tot;
add(x,i-1,a[node][v]);
sz[node]=sz[a[node][0]]+sz[a[node][1]];
}
void dfs(int node,int i){
if(!node||i==-1)return ;
r[i]+=rev[node];
s[i]+=sum[node];
dfs(a[node][0],i-1);
dfs(a[node][1],i-1);
}
}T;
void solve(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
T.add(a[i],30,1);
}
T.dfs(1,30);
int ans=0,x=0;
for(int i=30;i>=0;i--){
if(r[i]>s[i]){
x|=(1<<i);
ans+=s[i];
}else{
ans+=r[i];
}
}
cout<<ans<<' '<<x<<endl;
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);
solve();
return 0;
}