Library of Magic

本题两种情况分类讨论。设有

时, 的所有数都是 。我们可以二分出第一个 使得 即为 。询问次数为

时,直接二分就不好使了。不过仔细分析一些例子可以发现:一定可以找到一个 ,满足 最大不超过 ,直接枚举即可。

证明:当答案的某位是 时, 中有零个或两个当前位为 。考虑 的最高位 ,其为 ,那么 中有且只有一个第 位也为 。为了保证 ,我们选择 的第 位为 ,而 的第 位为 。这时,便有

找到 后, 一定在 中,在该区间内用类似的方法二分出 ,则最后一个数就一定在 中,直接问一次就好了。

使用 C++20,希望参选本题最优美代码奖。

#include <algorithm>
#include <iostream>
#include <ranges>
using namespace std;
istream& fin = cin;
ostream& fout = cout;
using ui = unsigned int;
using uli = unsigned long long int;
using li = long long int;
uli ask(uli l, uli r) {
  fout << "xor " << l << ' ' << r << endl;
  uli ans;
  fin >> ans;
  return ans;
}
int main(void) {
  ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
  size_t T;
  fin >> T;
  while (T--) {
    uli n;
    fin >> n;
    uli x = ask(1, n) == 0
                ? [n] {
                    for (uli i = 2; i < n; i *= 2) {
                      uli res = ask(1, i - 1);
                      if (res != 0) return res;
                    }
                    exit(300);
                  }()
                : [n] {
                    auto view = ranges::views::iota(1ull, n + 1) |
                                ranges::views::transform(
                                    [](uli v) -> bool { return ask(1, v); });
                    auto it = ranges::lower_bound(view, true);
                    return uli(it - view.begin()) + 1ull;
                  }();
    uli y = [n, x] {
      auto view = ranges::views::iota(x + 1, n + 1) |
                  ranges::views::transform(
                      [x](uli v) -> bool { return ask(x + 1, v); });
      auto it = ranges::lower_bound(view, true);
      return uli(it - view.begin()) + (x + 1);
    }();
    uli z = ask(y + 1, n);
    fout << "ans " << x << ' ' << y << ' ' << z << endl;
  }
  return 0;
}
posted @ 2024-11-08 20:45  MrPython  阅读(8)  评论(0)    收藏  举报  来源