标签:cf1416 XOR int siz son Inverse 对数 zh 逆序
题意:
给定数组 \(a[]\),找一个整数 \(x\),构造数组 \(b[]\) ,$b_i=a_i \oplus x $使得 \(b[]\) 中的逆序对数最少,其次使得 \(x\) 尽量小。输出最少逆序对数与 \(x\)
\(n\le 3e5, 0\le a_i\le 1e9\)
思路:
看到异或就要考虑一下xor字典树!
贪心从高到低考虑每一位。根据异或的性质,若x的这一位选0则所有数的这一位不变,若x的这一位选1则所有数的这一位取反(这会使所有正序对变成逆序对)
一边往xor字典树中加数,一边记录所有第1~k-1位完全相同的数字,第k位不变会有多少逆序对,第k位取反又会有多少逆序对
字典树的空间应该是一个先等比后相等的数列的和?这题开 30N 即可
(本来的思路是递归,从高位到低位不断把数组划成更小的子段,线性求01数组的逆序对数,后来发现不可行,因为要求的是前缀相同的子序列而非子段的逆序对数)
const int N = 3e5 + 5;
int son[N*30][2], siz[N*30], idx;
ll zh[33], ni[33];
void ins(int x)
{
int p = 0;
for(int k = 29; k >= 0; k--)
{
int u = (x>>k)&1;
if(u == 0) ni[k] += siz[son[p][1]];
else zh[k] += siz[son[p][0]];
if(!son[p][u]) son[p][u] = ++idx;
p = son[p][u]; siz[p]++;
}
}
main()
{
iofast;
int n; cin >> n; while(n--) {
int x; cin >> x; ins(x);
}
ll ans = 0, x = 0;
for(int k = 29; k >= 0; k--)
if(zh[k] < ni[k]) ans += zh[k], x |= (1<<k);
else ans += ni[k];
cout << ans << ' ' << x;
}
标签:cf1416,XOR,int,siz,son,Inverse,对数,zh,逆序 来源: https://www.cnblogs.com/wushansinger/p/15982687.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。