[CF1267I] Intriguing Selection 题解

考虑 n=3n=3 的情况,假设我们第一次询问 (a,b)(a,b),得到 a<ba<b,如果第二次询问仍然包含 aa 的话就可能得到前 33 名的排序了。

接着询问 bb 不好做,于是我们考虑询问另一个不相交的 (c,d)(c,d),得到 b<db<d,我们再询问一次 (a,c)(a,c) 的大小关系,不妨设 a<ca<c,此时我们可以询问 aa 与其他所有人的大小关系,因为存在两个比它大的大小关系不确定。

考虑这样一个算法,我们维护一个初始包含所有数的队列,每次依次取出 a,b,c,da,b,c,d 四个数,按照如上方法询问,之后再按 b,c,db,c,d 的顺序放回,这样一直做到只剩三个数为止,此时我们一定能保证这三个数中我们只知道一对的大小关系,结束即可。

#include <bits/stdc++.h>
using namespace std;
int n, mp[210][210];
int query(int a, int b) {
  if (mp[a][b] != -1)
    return mp[a][b];
  cout << "? " << a << " " << b << '\n';
  cout.flush();
  char c;
  cin >> c;
  return mp[a][b] = c == '<';
}
int main() {
  cin.tie(0)->sync_with_stdio(0);
  int T;
  cin >> T;
  while (T--) {
    cin >> n;
    n <<= 1;
    for (int i = 1; i <= n; i++)
      for (int j = 1; j <= n; j++)
        mp[i][j] = -1;
    vector<int> v;
    for (int i = 1; i <= n; i++)
      v.push_back(i);
    while (v.size() > 3) {
      int a = v.back();
      v.pop_back();
      int b = v.back();
      v.pop_back();
      int c = v.back();
      v.pop_back();
      int d = v.back();
      v.pop_back();
      if (!query(a, b))
        swap(a, b);
      if (!query(c, d))
        swap(c, d);
      if (!query(a, c))
        swap(a, c), swap(b, d);
      for (int i = 1; i <= n; i++) {
        if (i != a)
          query(i, a);
      }
      v.push_back(b), v.push_back(c), v.push_back(d);
    }
    cout << "! " << '\n';
    cout.flush();
  }
  return 0;
}
// 1 6 4 3 2 5
posted @ 2023-10-05 20:37  swiftqwq  阅读(15)  评论(0)    收藏  举报  来源