競技プログラミング日記

主に AtCoder の記事です

AtCoder Beginner Contest 281F

ABC281F

解法

桁ごとに独立に計算する. 上の桁から決めていく.

vector \(a\) に対して,各元の \(2^{k}\) の係数が \(0,1\) で分類する. それらを \(a^{(0,k)}, a^{(1,k)}\) とおく. \(f(k, a)\) を,\(x\) を動かしたときの \(x \oplus a\) の \(2^{j} , j \leq k\) の部分に対する答え とする.
Case: \(a^{(0,k)}\) が空のとき:
\(x\) の \(2^{k}\) の係数を \(1\) にすれば,\(x \oplus a^{(1,k)}\) の全ての元に対して, \(2^{k}\)の係数は \(0\) になる.
Case: \(a^{(1,k)}\) が空のとき:
\(x\) の \(2^{k}\) の係数を \(0\) にすれば,\(x \oplus a^{(0,k)}\) の全ての元に対して, \(2^{k}\)の係数は \(0\) になる.
Case : どちらも空でないとき
\(min(f(k-1,a^{(0,k)}),f(k-1,a^{(1,k)}))+2^{k}\) となる.

注意

演算の優先順位に注意. << と + は,+ 優先.

使っている記号,マクロ等 "https://ecsmtlir.hatenablog.com/entry/2022/12/23/131925"

int main() {
  ll n;
  cin >> n;
  vll a(n); rep(i,n) { cin >> a[i]; }

  auto f = [&](auto f, ll k , vll &b) -> ll {
    if(k == -1){
      return 0;
    }
   
    vvll v(2);
    rep(i,b.size()){ // rem: not i in b.size()
      ll x = (b[i]>>k&1);
      v[x].push_back(b[i]);
    }

    if(v[0].size() == 0) return f(f, k-1, v[1]);
    if(v[1].size() == 0) return f(f, k-1, v[0]);
   
    return min(f(f, k-1, v[0]), f(f, k-1, v[1])) + (1LL<<k);
  };
 
  cout << f(f, 35, a) << endl;

  return 0;
}