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;
}

浙公网安备 33010602011771号