CodeForces 1526F Median Queries

发布时间 2023-12-03 12:10:59作者: zltzlt

洛谷传送门

CF 传送门

首先,如果我们确定了 \(1, 2\)\(n - 1, n\) 的位置,我们就能求出原排列。因为题目给了 \(p_1 < p_2\),所以可以不考虑对称性。也就是说我们知道两个位置是 \(1, 2\)\(n - 1, n\) 但不确定究竟是 \(1, 2\) 还是 \(n - 1, n\) 也可以。

然后,如果我们确定了一对挨得够近的一对数 \(i, j\),用它们再去问剩下的,距离最大和次大的就是 \(1, 2\)\(n - 1, n\)。(有个 corner case,若 \(p_i + p_j = n - 1\),那么最大和次大值都有两个,注意判一下)

发现只要 \(|i - j| \le \frac{n - 4}{3}\),距离最大和次大的就是 \(1, 2\)\(n - 1, n\)

上面用了 \(2(n - 2)\) 次操作,还剩下 \(424\) 次操作留给随机化。随机问一些 \((a, b, c)\),如果回答 \(\le \frac{n - 4}{6}\),那它们两两距离都 \(\le \frac{n - 4}{3}\)。操作次数很充裕,随不到的概率 \(< 10^{-10}\)

code
// Problem: F. Median Queries
// Contest: Codeforces - Codeforces Round 723 (Div. 2)
// URL: https://codeforces.com/problemset/problem/1526/F
// Memory Limit: 256 MB
// Time Limit: 6000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 100100;

int n, a[maxn];
vector<int> vc[maxn];
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());

inline int ask(int x, int y, int z) {
	printf("? %d %d %d\n", x, y, z);
	fflush(stdout);
	scanf("%d", &x);
	return x;
}

void solve() {
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) {
		vector<int>().swap(vc[i]);
	}
	int mn = 1e9, p = -1, q = -1;
	for (int _ = 0; _ < 420; ++_) {
		int x, y, z;
		do {
			x = rnd() % n + 1;
			y = rnd() % n + 1;
			z = rnd() % n + 1;
		} while (x == y || x == z || y == z);
		int t = ask(x, y, z);
		if (t < mn) {
			mn = t;
			p = x;
			q = y;
		}
	}
	int mx = -1e9;
	for (int i = 1; i <= n; ++i) {
		if (i != p && i != q) {
			int t = ask(i, p, q);
			mx = max(mx, t);
			vc[t].pb(i);
		}
	}
	if ((int)vc[mx - 1].size() > 1 && ask(vc[mx][0], p, vc[mx - 1][0]) > ask(vc[mx][0], p, vc[mx - 1][1])) {
		swap(vc[mx - 1][0], vc[mx - 1][1]);
	}
	p = vc[mx][0];
	q = vc[mx - 1][0];
	a[p] = 1;
	a[q] = 2;
	for (int i = 1; i <= n; ++i) {
		if (i != p && i != q) {
			a[i] = ask(i, p, q) + 2;
		}
	}
	if (a[1] > a[2]) {
		for (int i = 1; i <= n; ++i) {
			a[i] = n - a[i] + 1;
		}
	}
	printf("! ");
	for (int i = 1; i <= n; ++i) {
		printf("%d ", a[i]);
	}
	putchar('\n');
	fflush(stdout);
	scanf("%d", &n);
	if (n == -1) {
		exit(0);
	}
}

int main() {
	int T = 1;
	scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}