CF1553H XOR and Distance
阿新 • • 發佈:2021-08-10
題目連結
Codeforces 1553H XOR and Distance
題目大意
給定一個長度為 \(n\) 的數列 \(a_i\) 和一個數字 \(k\),滿足 \(a_i< 2^k\),設
\[f(x)=\min_{i=1}^n\min_{j=i+1}^n|(a_i\oplus x)-(a_j\oplus x)| \]請對所有 \(0\leq x\leq 2^k-1\),求出 \(f(x)\) 。
\(1\leq k\leq 19\),\(2\leq n\leq2^k\),\(a_i\neq a_j\)
思路
建出字典樹,可以發現答案即為字典樹的所有相鄰葉子的距離最小值,考慮 \(x\)
好像只要每個 \(x\) 從 \(x\oplus highbit(x)\) 轉移過來就可以滿足這個條件了!但是這樣好像不能一次做完,因為這個轉移關係是一張 \(DAG\)
時間複雜度對了,考慮具體維護資訊,由於有左右兒子翻轉這個操作,在 \(Trie\) 的每個節點上維護 \(ans,mx,mn,len\)
維護是線性的,所以時間複雜度 \(O(k\cdot2^k)\) 。
Code
#include<iostream>
#include<stack>
#include<fstream>
#include<ctime>
#define rep(i,a,b) for(int i = (a); i <= (b); i++)
#define per(i,b,a) for(int i = (b); i >= (a); i--)
#define N 600000
#define K 20
#define Inf 0x3f3f3f3f
using namespace std;
int Gray[N], rev[N], ans[N], Log[N];
int n, k;
struct Trie{
struct node{
int ans, c[2];
int mn, mx, len;
} t[N*K];
int cnt;
int New(int k){
t[++cnt].ans = Inf;
t[cnt].len = 1<<k, t[cnt].mn = Inf, t[cnt].mx = -1;
return cnt;
}
void init(){ New(k), t[0].ans = Inf; }
void update(int x){
t[x].ans = min(t[t[x].c[0]].ans, t[t[x].c[1]].ans);
t[x].mn = Inf, t[x].mx = -1;
rep(i,0,1){
int y = t[x].c[i];
if(!y) continue;
t[x].mn = min(t[x].mn, t[y].mn + i*t[y].len);
t[x].mx = max(t[x].mx, t[y].mx + i*t[y].len);
}
int l = t[x].c[0], r = t[x].c[1];
if(l && r) t[x].ans = min(t[x].ans, t[r].mn+t[l].len-t[l].mx);
}
void insert(int n){
int x = 1;
stack<int> s;
per(i,k-1,0){
s.push(x);
int id = n>>i&1;
if(!t[x].c[id]) t[x].c[id] = New(i);
x = t[x].c[id];
}
t[x].mn = t[x].mx = 0;
while(!s.empty()) update(s.top()), s.pop();
}
void change(int x, int lev, int p){
if(x == 0) return;
if(lev == p){
swap(t[x].c[0], t[x].c[1]), update(x);
return;
}
change(t[x].c[0], lev-1, p), change(t[x].c[1], lev-1, p);
update(x);
}
void print(){
rep(i,1,cnt) cout<<i<<":"<<t[i].c[0]<<","<<t[i].c[1]
<<" "<<t[i].ans<<" "<<t[i].len<<' '<<t[i].mn<<","<<t[i].mx<<endl;
cout<<endl;
}
} Trie;
void init(){
Gray[0] = 0, Gray[1] = 1;
rep(i,1,k-1) rep(j,0,(1<<i)-1)
Gray[(2<<i)-j-1] = Gray[j]|(1<<i);
rep(i,0,(1<<k)-1) rev[i] = rev[i>>1]>>1 | ((i&1)<<(k-1));
rep(i,0,(1<<k)-1) Gray[i] = rev[Gray[i]];
rep(i,0,k-1) Log[1<<i] = i;
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>k;
int a;
Trie.init();
rep(i,1,n) cin>>a, Trie.insert(a);
init();
ans[0] = Trie.t[1].ans;
rep(i,1,(1<<k)-1){
Trie.change(1, k-1, Log[Gray[i]^Gray[i-1]]);
ans[Gray[i]] = Trie.t[1].ans;
}
rep(i,0,(1<<k)-1) cout<<ans[i]<<" ";
cout<<endl;
return 0;
}