CF2031F Penchick and Even Medians

lalaouye發表於2024-11-24

賽時墜機了,賽後把 F 做出來了。。

剛開始做不出來,後來注意到樣例輸出了長度為 \(n-2\) 的詢問,啟發我對於每個相鄰數對 \((i,i+1)\),將其刪去再進行詢問,其中 \(i\) 為奇數,共消耗 \(50\) 次。然後我們對輸出的兩個數 \(x,y\) 進行討論:

  1. 如果 \(x,y\) 滿足 \(x=\frac n 2,y=\frac n 2 +1\),則說明刪去的兩個數其中一個數小於 \(\frac n 2\),一個數大於 \(\frac n 2 +1\)。這種情況貌似對答案並不影響。

  2. 如果 \(x,y\) 滿足 \(x<\frac n 2,y > \frac n 2 + 1\),則說明刪除的數正是 \(\frac n 2\)\(\frac n 2 +1\),這種情況是好處理的。

  3. 如果 \(x,y\) 滿足 \(x=\frac n 2,y> \frac n 2+1\),則說明 \(\frac n 2+1\) 正好在這個數對裡面,將其記錄下來。

  4. 如果 \(x,y\) 滿足 \(x<\frac n 2,y=\frac n 2+1\),跟上面的情況類似。

  5. 如果 \(x,y\) 滿足 \(x<\frac n 2,y=\frac n 2\),這種情況有些複雜,也是本題的重點,數對中的數都大於等於 \(\frac n 2+1\)

  6. 如果 \(x,y\) 滿足 \(x=\frac n 2+1,y>\frac n 2+1\),跟上面情況類似。

發現最麻煩的是第 \(5,6\) 類點對,我們把第 \(5\) 類點對存入一個陣列,第 \(6\) 類存入另一個陣列,現在考慮找到包含 \(\frac n 2\) 的點對和 \(\frac n 2 +1\) 的點對,怎麼找呢?其實也是簡單的,直接詢問第一個陣列的第一個點對與第二個陣列的第一個點對,第一個陣列的第二個點對與第二個陣列的第二個點對......這樣子只要結果輸出了 \(\frac n 2\)\(\frac n 2+1\),我們就能夠確定包含這兩個數的兩個點對了。

找到點對後怎麼處理都行,算一下操作次數,首先要花 \(50\) 次列舉點對,然後再最多花 \(25\) 次找兩個點對,最後花 \(4\) 次確定位置,總共 \(79\) 次,可以透過。

程式碼很醜,僅供參考:

#include <bits/stdc++.h>
#define rep(i, l, r) for (int i (l); i <= r; ++ i)
#define rrp(i, l, r) for (int i (r); i >= l; -- i)
#define pii pair <int, int>
#define eb emplace_back
#define inf 1000000000000
using namespace std;
constexpr int N = 100 + 5, K = 10;
typedef unsigned long long ull;
typedef long long ll;
inline int rd () {
  int x = 0, f = 1;
  char ch = getchar ();
  while (! isdigit (ch)) {
    if (ch == '-') f = -1;
    ch = getchar ();
  }
  while (isdigit (ch)) {
    x = (x << 1) + (x << 3) + ch - 48;
    ch = getchar ();
  }
  return x * f;
}
int n;
pii ask1 (int x, int y) {
  cout << "? " << n - 2 << " ";
  rep (i, 1, n) {
    if (i != x && i != y) cout << i << " ";
  }
  cout << endl;
  cin >> x >> y;
  return pii (x, y);
}
pii ask2 (int a, int b, int c, int d) {
  cout << "? 4 " << a << " " << b << " " << c << " " << d << endl; 
  int x, y;
  cin >> x >> y;
  return pii (x, y);
}
int a1[N], n1, a2[N], n2, tt;
void motherfucker () {
  ++ tt;
  cin >> n; n1 = n2 = 0;
  int f1 = 0, f2 = 0;
  int x = 0, y = 0, z = 0;
  rep (i, 1, n) {
    pii t = ask1 (i, i + 1);
    if (t.first == n / 2 && t.second == n / 2 + 1) {
      if (! f1) f1 = i; else f2 = i;
    } else {
      if (t.first == n / 2 && t.second > n / 2 + 1) {
        y = i;
      } else 
      if (t.first < n / 2 && t.second == n / 2 + 1) {
        x = i;
      } else {
        if (t.first < n / 2 && t.second > n / 2 + 1) {
          z = i; ++ i; continue;
        }
        if (t.first < n / 2 && t.second == n / 2) a2[++ n2] = i;
        else a1[++ n1] = i;
      }
    }
    ++ i;
  }
  if (z) {
    if (! f1) {
      rep (i, 1, n1) f1 = a1[i];
      rep (i, 1, n2) f2 = a2[i];
    } else {
      if (! f2) {
        rep (i, 1, n1) f2 = a1[i];
        rep (i, 1, n2) f2 = a2[i];
      }
    }
    pii t = ask2 (f1, f1 + 1, f2, z);
    if (t.first == n / 2 || t.second == n / 2) {
      cout << "! " << z << " " << z + 1 << endl; 
    } else cout << "! " << z + 1 << " " << z << endl;
    return ;
  } else {
    int mn = min (n1, n2);
    int l = 0, r = 0;
    rep (i, 1, mn) {
      pii t = ask2 (a1[i], a1[i] + 1, a2[i], a2[i] + 1);
      if (t.first == n / 2 || t.second == n / 2) x = a1[i];
      else l = a1[i];
      if (t.first == n / 2 + 1 || t.second == n / 2 + 1) y = a2[i];
      else r = a2[i];
    }
    if (n2)
    rep (i, n2 + 1, n1) {
      pii t = ask2 (a1[i], a1[i] + 1, a2[1], a2[1] + 1);
      if (t.first == n / 2 || t.second == n / 2) x = a1[i];
      else l = a1[i];
      if (t.first == n / 2 + 1 || t.second == n / 2 + 1) y = a2[1];
      else r = a2[1];
    }
    if (n1)
    rep (i, n1 + 1, n2) {
      pii t = ask2 (a1[1], a1[1] + 1, a2[i], a2[i] + 1);
      if (t.first == n / 2 || t.second == n / 2) x = a1[1];
      else l = a1[1];
      if (t.first == n / 2 + 1 || t.second == n / 2 + 1) y = a2[i];
      else r = a2[i];
    }
    if (f1) l = f1, r = f1 + 1;
    if (! l) l = r + 1; if (! r) r = l + 1;
    pii t = ask2 (l, r, x, y);
    int ans1 = 0, ans2 = 0;
    if (t.first == n / 2 || t.second == n / 2) {
      ans1 = x;
    }
    if (t.first == n / 2 + 1 || t.second == n / 2 + 1) {
      ans2 = y;
    }
    t = ask2 (l, r, x + 1, y);
    if (t.first == n / 2 || t.second == n / 2) {
      ans1 = x + 1;
    }
    if (t.first == n / 2 + 1 || t.second == n / 2 + 1) {
      ans2 = y;
    }
    t = ask2 (l, r, x, y + 1);
    if (t.first == n / 2 || t.second == n / 2) {
      ans1 = x;
    }
    if (t.first == n / 2 + 1 || t.second == n / 2 + 1) {
      ans2 = y + 1;
    }
    t = ask2 (l, r, x + 1, y + 1);
    if (t.first == n / 2 || t.second == n / 2) {
      ans1 = x + 1;
    }
    if (t.first == n / 2 + 1 || t.second == n / 2 + 1) {
      ans2 = y + 1;
    }
    cout << "! " << ans1 << " " << ans2 << endl;
  }
}
int main () {
  // freopen ("1.in", "r", stdin);
  int T; cin >> T;
  for (; T; -- T) motherfucker ();
}

相關文章