CF1851F - Lisa and the Martians

发布时间 2023-08-28 17:21:06作者: Ciaxin

题目描述

Lisa was kidnapped by martians! It okay, because she has watched a lot of TV shows about aliens, so she knows what awaits her. Let's call integer martian if it is a non-negative integer and strictly less than $ 2^k $ , for example, when $ k = 12 $ , the numbers $ 51 $ , $ 1960 $ , $ 0 $ are martian, and the numbers $ \pi $ , $ -1 $ , $ \frac{21}{8} $ , $ 4096 $ are not.

The aliens will give Lisa $ n $ martian numbers $ a_1, a_2, \ldots, a_n $ . Then they will ask her to name any martian number $ x $ . After that, Lisa will select a pair of numbers $ a_i, a_j $ ( $ i \neq j $ ) in the given sequence and count $ (a_i \oplus x) \& (a_j \oplus x) $ . The operation $ \oplus $ means Bitwise exclusive OR, the operation $ \& $ means Bitwise And. For example, $ (5 \oplus 17) \& (23 \oplus 17) = (00101_2 \oplus 10001_2) \& (10111_2 \oplus 10001_2) = 10100_2 \& 00110_2 = 00100_2 = 4 $ .

Lisa is sure that the higher the calculated value, the higher her chances of returning home. Help the girl choose such $ i, j, x $ that maximize the calculated value.


solution

1、分析

对于公式 $ t = (a_i \oplus x) \& (a_j \oplus x) $ 来讲,其中 $ a_i \& a_j $ 是一个固定的答案,$ \oplus x $ 只是对这个答案的调解。

对于 $ a_i $ 与 $ a_j $ 二进制的第 $ k $ 位。

  • 假设均为 $ 1 $,那么 $ x $ 的该位置上应该为 \(0\),以确保 $ t $ 的第 $ k $ 为也为 $ 1 $,使得答案最优。

  • 假设均为 $ 0 $,那么 $ x $ 的该位置上应该为 \(1\),以确保 $ t $ 的第 $ k $ 为也为 $ 1 $,使得答案最优。

  • 如果第 $ k $ 位上的值不相等,那么不管怎么异或,它们的第 $ k $ 上永远是 \(0 , 1\),最终答案的第 $ k $ 位也一定为 \(0\)

2、最大值(答案)

对于每个 $ i $ 来讲,$ 0 $ 的个数是固定的。

那么,就要找到一个每一位上不相同的数最小的数作为 $ j $,即 $ d = a_i \oplus a_j $ 的最小值。

就能使得 $ a_i $ 作为其中答案的最大值。

考虑到最终答案为 $ d \oplus 2 ^ { k } $ 的形式,所以求全局最小值即可。

这个地方用 01trie 解决即可。

3、$ x $ 的值

既然已经求得了最终的答案,那么按照 \(1\) 中所讲,只将 $ a_i , a_j = 0$ 的位置设为 \(1\) 即可。


code

scanf("%d%d", &n, &k);
for (int i = 1, j; i <= n; i ++ ) {
    scanf("%d", &a[i]);
    j = query_min(a[i]); // 查询 min{a[i]^a[j]} 的j的编号
    if (j != -1 && ans >= (res = a[j] ^ a[i])) {
        ans = res; xi = i; xj = j;
    }
    insert(i);
}
x = (~(a[xi] | a[xj])) & ((1 << k) - 1);
cout << xj << ' ' << xi << ' ' << x << '\n';