CF1416C XOR Inverse 题解

一道十分不错的分治题。

因为要进行异或操作,所以先将所有数拆成二进制数。

可以知道的是对于每一个二进制数,比较时是先比较最高位,然后接着往下面比,直到同一位上一个为 \(1\),一个为 \(0\)

所以对于每两个不相同的二进制数,只要对它们第一个不同的地方异或 \(1\),即可交换两数大小。

那么我们可以从 \(2^{30}\) 往下找,找到每一位上对应的数字为 \(1\)\(0\)

由于每一位上只有 \(0\)\(1\),所以可以 \(O(n)\) 处理出来这一位上的顺序对与逆序对个数,顺序即是将这一位异或 \(1\) 后的逆序对个数。如果顺序对的个数小于逆序对的个数,说明异或 \(1\) 以后得到的解更优,就将答案累计上。

统计完一个数位以后,会将所有数以此位上的数字分成 \(0\)\(1\),那么这些数字因为这个位上相同,所以要比较下一位,那么再利用 \(O(n\log{n})\) 的复杂度进行排序,然后分别处理 \(0\)\(1\) 的区间。最后将下一位的逆序对与顺序对的个数累加,再判断顺序对是否大于逆序对个数,再累加答案即可。

最后求出异或的数 \(x\) 后,将 \(a_i\) 异或上 \(x\),最后离散化加树状数组统计逆序对个数。

递归实现,利用了分治思想,复杂度 \(O(30\times n\log{n})\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#define int long long 
using namespace std;
const int N=3e5+5;
int n,a[N],ans,f[N],cnt,p1[35],p2[35];
struct node
{
	int data,name;
}t[N],s[N];
int cmp(node fi,node se)
{
	if(fi.data==se.data)return fi.name<se.name;
	return fi.data<se.data;
}
int cmp2(node fi,node se)
{
	return fi.name<se.name;
}
inline int lowbit(int x)
{
	return x&-x;
}
void update(int x)
{
	while(x)
	{
		f[x]++;
		x-=lowbit(x);
	}
}
int search(int x)
{
	int sum=0;
	while(x<=cnt)
	{
		sum+=f[x];
		x+=lowbit(x);
	}
	return sum;
}
void dfs(int i,int beg,int ed)
{
	if(beg>=ed)return;
	if(i<0)return;
	bool ss=((a[beg]&(1<<i)));
	int bef=beg,sum1=0,sum2=0,tot1=0,tot2=0;
	for(int j=beg;j<=ed;j++)
	{	
		int x=s[j].name;
		if(((a[x]&(1<<i))>0)!=ss)
		{
			if(ss==1)tot1+=sum2*(j-bef);
			if(ss==0)tot2+=sum1*(j-bef);
			ss=((a[x]&(1<<i)));
			bef=j;
		}
		sum1+=((a[x]&(1<<i))>0),sum2+=((a[x]&(1<<i))==0);
		s[j].data=((a[x]&(1<<i))>0);
	}
	sort(s+beg,s+ed+1,cmp);
	if(ss==1)tot1+=sum2*(ed-bef+1);
	if(ss==0)tot2+=sum1*(ed-bef+1);
	dfs(i-1,beg,ed-sum1);
	dfs(i-1,beg+sum2,ed);
	p1[i]+=tot1;
	p2[i]+=tot2;
}
signed main()
{
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]),s[i].name=i;
	dfs(30,1,n);
	for(int i=0;i<=30;i++)if(p2[i]>p1[i])ans^=(1<<i);
	for(int i=1;i<=n;i++)
	{
		t[i].name=i;
		t[i].data=a[i]^ans;
	}
	sort(t+1,t+1+n,cmp);
	int bef=-1;
	for(int i=1;i<=n;i++)
	{
		if(t[i].data!=bef)cnt++;
		bef=t[i].data;
		t[i].data=cnt;
	}
	sort(t+1,t+1+n,cmp2);
	int tot=0;
	for(int i=1;i<=n;i++)
	{
		tot+=search(t[i].data+1);
		update(t[i].data);
	}
	printf("%lld %lld",tot,ans);
	return 0;
}
posted @ 2023-02-24 13:16  Gmt丶Fu9ture  阅读(52)  评论(0)    收藏  举报