CF1553H XOR and Distance 题解

Codeforces
Luogu
Thanks to x义x

Description.

给定一个长度为 \(n\) 的序列 \(\{a_i\}\),保证 \(\forall i\in[1,n],a_i\in[0,2^k)\),对所有 \(x\in[0,2^k)\),求出 \(\min_{i,j\in[0,2^k)\land i\not=j}\left|(a_i\oplus x)-(a_j\oplus x)\right|\)

Solution.

位运算这类题,基本都是先考虑逐位确定的方式来做。
我们先考虑找一些性质,手模了 样例1 后并没有发现有什么优良的性质。
因为它是有一些 bit 为 \(1\),然后有些为 \(1\) 的可以是 \(-1\) 可能让答案变小。
所以贪心貌似行不通,可以考虑直接硬上。
维护一个选好后 \(d\) 位后的最大最小值,记为 \(F\),同时还需要维护当前能找到的最大值和最小值。
考虑如何从 \(d\) 变成 \(d+1\),最大值和最小值很好转移,我们需要考虑 \(F\) 怎么转移。
找出 \(l\)\(r\) 使得 \(l\oplus r=2^d\)\(l\le r\)
然后,我们按照答案中的 \(a_i\)\(a_j\) 的情况分类。
分成两类,一类是 \(v\&2^d=2^d\),一类是 \(v\&2^d=0\)
如果两者的种类相同,那他们这一位的权值是 \(0\),不变。
如果两者种类不同,那他们这一位会相差一个 \(2^d\),直接转移即可。
复杂度 \(O(2^k\times k+n)\)

Coding.

点击查看蒟蒻代码
//是啊……你就是那只鬼了……所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<'0'||c>'9';c=getchar()) if(c=='-') f=1;
	for(;c>='0'&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	if(f) x=-x;
}/*}}}*/
int N,n,F[524289],mx[524289],mn[524289];const int INF=1e9;
int main()
{
	read(N),read(n);for(int i=0;i<(1<<n);i++) mn[i]=F[i]=INF,mx[i]=-INF;
	for(int i=1,x;i<=N;i++) read(x),mx[x]=mn[x]=0;
	for(int d=0;d<n;d++) for(int r=0;r<(1<<n);r++) if((r>>d)&1)
	{
		int l=r-(1<<d);F[l]=F[r]=min(F[l],F[r]);
		F[l]=min(F[l],mn[r]-mx[l]+(1<<d)),F[r]=min(F[r],mn[l]-mx[r]+(1<<d));
		int mnl=mn[l],mnr=mn[r],mxl=mx[l],mxr=mx[r];
		mn[l]=min(mnl,mnr+(1<<d)),mn[r]=min(mnr,mnl+(1<<d));
		mx[l]=max(mxl,mxr+(1<<d)),mx[r]=max(mxr,mxl+(1<<d));
	}
	for(int i=0;i<(1<<n);i++) printf("%d ",F[i]);
	return putchar('\n'),0;
}
原文地址:https://www.cnblogs.com/pealfrog/p/15056372.html