Loading

CF1896G Pepe Racing 题解

可爱的 ad-hoc。

我们还是有序地思考问题吧。考虑每次确定最大值。

搞出第一个最大值相当容易:我们对每 \(n\) 个查询一下,得到 \(n\) 个最大值,在这 \(n\) 个里求一次就行。

然后把这个最大值去掉,考虑再搞一个出来,假设这个最大值在第 \(k\) 组里。

继续暴力显然会炸的,但是我们可以直接保留 \(n - 1\) 组的最大值。从 \(n - 1\) 组里随便选一个非最大值的值放到第 \(k\) 组里,查询第 \(k\) 组的就好了。

现在操作次数是 \(n + 1 + 2(n^2 - n + 1 - 1) = 2n^2 - n + 1\)。如何再优化掉 \(n\) 次?

我们看一下哪里边界可以再榨取一点效率:

考虑到只剩下 \(2n - 1\) 个人时,一定有 \(n - 1\) 组只有一个人,另外一组有 \(n\) 个人了。那么此时,每组的最大值其实就是剩下的前 \(n\) 大。显然,\(n\) 人组里非最大的 \(n - 1\) 个值,在它们原来的组里也不是最大值,所以一定小于那些一人组里的人。

对这 \(n\) 个人,我们可以用 \(n - 1\) 次操作辨别。于是 \(2n \to n\),总次数 \(2n^2 - 2n + 1\)

经验:像这种限制是一个式子的题可能就是构造而不是 DP。我们考虑将操作次数控制在一个量级内,然后对边界进行优化打磨方案。

#include <bits/stdc++.h>
#define int long long
#define Misaka namespace
#define Network std
using Misaka Network;

const int N = 27;
set<int> g[N];
int n, mx[N];

int ask(int id){
  cout << "? ";
  for(int x: g[id]) cout << x << " ";
  cout << endl;
  int res; cin >> res; return res;
}

pair<int, int> askw(){
  cout << "? ";
  for(int i = 1; i <= n; i ++) cout << mx[i] << " ";
  cout << endl;
  int res; cin >> res;
  for(int i = 1; i <= n; i ++) if(res == mx[i]) return {i, res};
  return {-1, -1};
}

void del(int id, int x){
  g[id].erase(x), mx[id] = -1;
  int nd = n - g[id].size();
  for(int i = 1; i <= n; i ++){
    if(i != id){
      vector<int> delt;
      for(int xx: g[i]){
        if(nd && xx != mx[i]){
          g[id].insert(xx), nd --;
          delt.push_back(xx);
        }
      }
      for(int xx: delt) g[i].erase(xx);
    }
  }
}

void solve(){
  cin >> n;
  for(int i = 1; i <= n; i ++) g[i].clear();
  for(int i = 1; i <= n * n; i ++){
    int id = (i - 1) / n + 1;
    g[id].insert(i);
    if(i % n == 0) mx[id] = ask(id);
  }

  vector<int> ans;
  auto [gr, val] = askw();
  ans.push_back(val), del(gr, val);
  int pre = gr;

  for(int i = 2; i + 2 * n - 1 <= n * n; i ++){
    mx[pre] = ask(pre);
    auto [xx, yy] = askw();
    ans.push_back(yy), del(xx, yy);
    pre = xx;
  }
  //total : n + 1 + 2 * (n^2 - 2n + 1 - 2 + 1) = n + 1 + 2n^2 - 4n = 2n^2 - 3n + 1, n left

  mx[pre] = ask(pre);
  set<int> lst; vector<int> bkup;
  for(int i = 1; i <= n; i ++) lst.insert(mx[i]);
  for(int xxx: g[pre]) if(xxx != mx[pre]) bkup.push_back(xxx);

  for(int i = n; i >= 2; i --){
    cout << "? ";
    for(int x: lst) cout << x << " ";
    for(int j = i + 1; j <= n; j ++) cout << bkup[j - i - 1] << " ";
    cout << endl;
    int res; cin >> res; lst.erase(res); ans.push_back(res);
  }
  ans.push_back(*lst.begin());

  cout << "! ";
  for(int x: ans) cout << x << " ";
  cout << endl;
  
}

signed main(){
  ios::sync_with_stdio(0), cin.tie(0);
  int t; cin >> t;
  while(t --) solve();
  return 0;
}
posted @ 2026-08-11 14:32  Trent900  阅读(9)  评论(1)    收藏  举报