1. 程式人生 > 其它 >[CF1553H] XOR and Distance

[CF1553H] XOR and Distance

\(\text{Problem}:\)XOR and Distance

\(\text{Solution}:\)

首先策略是,最高一位 \(a_{i}\oplus x\)\(a_{j}\oplus x\) 不同,使得這個最高位最低。然後儘量多的使後面位置 \(a_{i}\oplus x\)\(a_{j}\oplus x\) 不同且符號與最高位相反。

這裡普通的做法是利用 \(01\text{ trie}\) 求解,實現較為複雜。CF 上某位神仙提供了一種複雜度與實現難度更低的做法

強制 \(f(x)\) 只能使用 \(a\) 中的一個子集,其中元素 \(p\) 滿足二進位制下,只有後 \(k\)

位可能與 \(x\) 不同。在此限制下,設 \((x,k)\) 表示此時可用元素的集合,\(f(x,k)\) 表示答案,\(ma(x,k)\)\(mi(x,k)\) 表示 \(x\oplus p\) 的最大值與最小值。考慮從 \(k\) 轉移到 \(k+1\) 時,有以下幾種轉移:

  • \(f(x,k)\rightarrow f(x,k+1)\),由於 \((x,k)\) 對應集合一定是 \((x,k+1)\) 對應集合的子集,故直接轉移。
  • 下面令 \(x,y\) 是一對只在 \(k+1\) 位上不同的數(沒有其他的轉移狀態)。顯然,\((a_{i}\oplus x)-(a_{j}\oplus x)=(a_{i}\oplus y)-(a_{j}\oplus y)\)
    ,故 \(f(y,k)\rightarrow f(x,k+1)\)
  • 否則,可以看作從 \(x\)\(y\) 的對應集合中分別取出一個元素來更新 \(f_{x,k+1}\)。不難發現,一定有 \(2^{k+1}\) 的貢獻。此時,從 \((y,k)\) 對應集合中取一個與 \(y\) 異或最小的元素,即 \(mi(y,k)\),和 \(x\) 異或,再減去 \(ma(x,k)\),這顯然是當前的最小答案。故有 \(2^{k+1}+mi(y,k)-ma(x,k)\rightarrow f(x,k+1)\)。同理,對於 \(y\) 的轉移,有 \(2^{k+1}+mi(x,k)-ma(y,k)\rightarrow f(y,k+1)\)

然後考慮 \(ma\)\(mi\) 的更新。根據我們的定義,\((x,k+1)\) 對應集合就是將 \((x,k)\)\((y,k)\) 合併。這樣就可以快速更新 \(ma(x,k+1)\)\(mi(x,k+1)\)

注意一對 \(x,y\) 只轉移一次,不能重複轉移。總時間複雜度 \(O(k2^{k})\)

\(\text{Code}:\)

#include <bits/stdc++.h>
#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=1000010;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,K,f[N],ma[N],mi[N];
signed main()
{
	n=read(), K=read();
	memset(f,0x3f,sizeof(f));
	memset(ma,-0x3f,sizeof(ma));
	memset(mi,0x3f,sizeof(mi));
	for(ri int i=1;i<=n;i++)
	{
		int x=read();
		ma[x]=mi[x]=0;
	}
	for(ri int i=0;i<K;i++)
	{
		for(ri int x=0;x<(1<<K);x++)
		{
			if((x>>i)&1) continue;
			int y=x^(1<<i);
			f[x]=f[y]=min(f[x],f[y]);
			f[x]=min(f[x],(1<<i)+mi[y]-ma[x]);
			f[y]=min(f[y],(1<<i)+mi[x]-ma[y]);
			int px,py,qx,qy;
			px=ma[x], py=ma[y], qx=mi[x], qy=mi[y];
			ma[x]=max(ma[x],py+(1<<i));
			ma[y]=max(ma[y],px+(1<<i));
			mi[x]=min(mi[x],qy+(1<<i));
			mi[y]=min(mi[y],qx+(1<<i));
		}
	}
	for(ri int i=0;i<(1<<K);i++) printf("%d ",f[i]);
	puts("");
	return 0;
}
夜畔流離回,暗歎永無殿。 獨隱萬花翠,空寂亦難遷。 千秋孰能為,明滅常久見。 但得心未碎,踏遍九重天。