想定解とは異なると思われる解法で解きました。
問題概要
(インタラクティブ問題)
の順列 がある。この順列を質問をして当てたい。質問では、整数 を質問し、 ならば の値を、 ならば の値を知ることができる。
質問を 回以下行い、順列 を答えよ。
解法
個の要素を 個のペアに分け、定数個の例外を除いて各ペアについて 3 回の質問で値を特定します。以下、ペアになっている要素を とします。
何個かの の値について の値と得られる値の関係を調べる実験を行うと、 や のときに得られる値の種類が最も多くなるので、それらの質問をします。具体的には、 を質問した答えを 、 を質問した答えを とし、 の値で場合分けします。なお、場合分けは番号が小さいものをより優先するとします。
(1) のとき
より ですが、 となることはないので です。従って となります。また、 なので、 となります。
(2) のとき
より ですが、 となることはないので です。従って となります。また、 なので、 となります。
(3) のとき
より , より なので が成立します。よって、 より としてあり得る組は の 2 通り存在します。
そこで、 として質問すると、答えが のときは , のときは となり、 なのでこれらを判別することができます。
(4) のとき より が、 より がわかります。また、 のときは より矛盾が生じ、 のときは より矛盾が生じるため、 としてあり得る組は の 5 通り存在します。
として質問したときの答えを 、 として質問したときの答えを とすると、 のとき はそれぞれ となるので、 とならない最初の 3 通りは判別することはできます。
また、 として質問したときの答えを とすると、 のときそれぞれ となり、残りの 2 通りも判別することができます。
(5) のとき より であり、 のときは と矛盾が生じるので です。 は順列より なので です。
(6) のとき より であり、 のときは と矛盾が生じるので です。 は順列より なので です。
(7) のとき より 、 より です。また、 のときは と矛盾が生じ、 のときは と矛盾が生じるので、 としてあり得る組は の 3 通り存在します。
として質問したときの答えを 、 として質問したときの答えを とすると、 のとき はそれぞれ となり、これらを判別することができます。
(8) のとき より 、 より です。また、 のときは と矛盾が生じ、 のときは と矛盾が生じるので、 としてあり得る組は の 3 通り存在します。
として質問したときの答えを 、 として質問したときの答えを とすると、 のとき はそれぞれ となり、これらを判別することができます。
以上より、次に示す方法で を特定することができます。
として質問したときの答えを 、 として質問したときの答えを とする。
(1) のとき、
(2) のとき、
(3) のとき、 として質問し、その答えを とすると
(3-1) のとき、
(3-2) そうでないとき、
(4) のとき、 として質問しその答えを 、 として質問しその答えを とする。
(4-1) のとき、
(4-2) のとき、
(4-3) のとき、
(4-4) のとき、 として質問しその答えを とする。
(4-4-1) のとき、
(4-4-2) そうでないとき、
(5) のとき、
(6) のとき、
(7) のとき、 として質問しその答えを とする。
(7-1) のとき、
(7-2) そうでないとき、 として質問しその答えを とする。
(7-2-1) のとき、
(7-2-2) そうでないとき、
(8) のとき、 として質問しその答えを とする。
(8-1) のとき、
(8-2) そうでないとき、 として質問しその答えを とする。
(8-2-1) のとき、
(8-2-2) そうでないとき、
の値を特定するのに 3 回以上質問しなければならないときもありますが、そのような場合でも 5 回以内の質問で特定することができ、このケースは十分小さい定数回しか出現しないため、クエリ数の上限以内で のすべての要素が特定できます。
実装
#include <bits/stdc++.h> using namespace std; int main(){ int T; cin >> T; for (int i = 0; i < T; i++){ int n; cin >> n; vector<pair<int, int>> P; for (int j = 0; j < n / 2; j++){ P.push_back(make_pair(j * 2, j * 2 + 1)); } if (n % 2 == 1){ P.push_back(make_pair(n - 2, n - 1)); } int m = P.size(); vector<int> p(n); for (int j = 0; j < m; j++){ int a = P[j].first; int b = P[j].second; cout << "? " << 1 << ' ' << a + 1 << ' ' << b + 1 << ' ' << n - 1 << endl; int res1; cin >> res1; cout << "? " << 2 << ' ' << a + 1 << ' ' << b + 1 << ' ' << 1 << endl; int res2; cin >> res2; if (res2 == 1){ p[a] = 1; p[b] = res1; } else if (res1 == n){ p[a] = res2; p[b] = n; } else if (3 <= res1 && res1 <= n - 2 && 3 <= res2 && res2 <= n - 2){ cout << "? " << 1 << ' ' << a + 1 << ' ' << b + 1 << ' ' << res2 << endl; int res3; cin >> res3; if (res3 == res2){ p[a] = res1; p[b] = res2; } else { p[a] = res2; p[b] = res1; } } else if (res1 == n - 1 && res2 == 2){ cout << "? " << 1 << ' ' << a + 1 << ' ' << b + 1 << ' ' << 1 << endl; int res3; cin >> res3; cout << "? " << 2 << ' ' << a + 1 << ' ' << b + 1 << ' ' << n - 1 << endl; int res4; cin >> res4; if (res3 == 1 && res4 == n){ p[a] = n; p[b] = 1; } else if (res3 == 2 && res4 == n){ p[a] = n; p[b] = 2; } else if (res3 == 1 && res4 == n - 1){ p[a] = n - 1; p[b] = 1; } else { cout << "? " << 1 << ' ' << a + 1 << ' ' << b + 1 << ' ' << 2 << endl; int res5; cin >> res5; if (res5 == 2){ p[a] = n - 1; p[b] = 2; } else { p[a] = 2; p[b] = n - 1; } } } else if (res1 == 2 && res2 == 2){ p[a] = 2; p[b] = 1; } else if (res1 == n - 1 && res2 == n - 1){ p[a] = n; p[b] = n - 1; } else if (res1 < n - 1 && res2 == 2){ cout << "? " << 1 << ' ' << a + 1 << ' ' << b + 1 << ' ' << 1 << endl; int res3; cin >> res3; if (res3 == 1){ p[a] = res1; p[b] = 1; } else { cout << "? " << 1 << ' ' << a + 1 << ' ' << b + 1 << ' ' << 2 << endl; int res4; cin >> res4; if (res4 == 2){ p[a] = res1; p[b] = 2; } else { p[a] = 2; p[b] = res1; } } } else if (res1 == n - 1 && res2 > 2){ cout << "? " << 2 << ' ' << a + 1 << ' ' << b + 1 << ' ' << n - 1 << endl; int res3; cin >> res3; if (res3 == n){ p[a] = n; p[b] = res2; } else { cout << "? " << 2 << ' ' << a + 1 << ' ' << b + 1 << ' ' << n - 2 << endl; int res4; cin >> res4; if (res4 == n - 1){ p[a] = n - 1; p[b] = res2; } else { p[a] = res2; p[b] = n - 1; } } } } cout << "!"; for (int j = 0; j < n; j++){ cout << ' ' << p[j]; } cout << endl; } }