CF1416C XOR Inverse 题解

一道十分不错的分治题。

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

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

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

那么我们可以从 230 往下找,找到每一位上对应的数字为 10

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

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

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

递归实现,利用了分治思想,复杂度 O(30×nlogn)

#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 @   Gmt丶Fu9ture  阅读(34)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示