[CF1553H] XOR and Distance
阿新 • • 發佈:2021-10-11
\(\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\)
- \(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)\)
- 否則,可以看作從 \(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;
}
夜畔流離回,暗歎永無殿。
獨隱萬花翠,空寂亦難遷。
千秋孰能為,明滅常久見。
但得心未碎,踏遍九重天。