题意
传送门 AtCoder practice contest B Interactive Sorting
题解
归并排序 + 二分
对于 n = 26 n = 26 n=26 的情况,归并排序最坏情况下需要 99 99 99 次比较。对于 n = 5 n=5 n=5 的情况,比较 c 1 , c 2 c_1,c_2 c1,c2,再比较 c 3 , c 4 c_3,c_4 c3,c4,接着比较两组数据的最小者(不妨假设为 c 1 c_1 c1),此时得到了一个有序的三元组 c 1 , c 3 , c 4 c_1,c_3,c_4 c1,c3,c4,二分求解 c 5 c_5 c5 的位置并插入,此时 c 1 c_1 c1 右侧的元素至多为 3 3 3,再次二分插入 c 2 c_2 c2 即可。由于插入一个有序三元组需要二分比较的次数为 2 2 2,故总比较次数 3 + 2 + 2 = 7 3+2+2=7 3+2+2=7 满足条件。
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
auto cmp = [&](int a, int b) {
cout << "? " << char(a + 'A') << ' ' << char(b + 'A') << endl;
char c;
cin >> c;
return c == '<';
};
function<void(vector<int> &)> merge_sort = [&](vector<int> &a) {
int n = a.size();
if (n <= 1) {
return;
}
int m = n / 2;
vector<int> b(a.begin(), a.begin() + m);
vector<int> c(a.begin() + m, a.end());
merge_sort(b);
merge_sort(c);
for (int ai = 0, bi = 0, ci = 0; ai < n; ++ai) {
if (ci == (int)c.size() || (bi < (int)b.size() && cmp(b[bi], c[ci]))) {
a[ai] = b[bi++];
} else {
a[ai] = c[ci++];
}
}
};
int n, q;
cin >> n >> q;
auto output = [&](vector<int> &ord) {
cout << "! ";
for (int i : ord) {
cout << char(i + 'A');
}
cout << endl;
};
if (n == 26) {
vector<int> ord(n);
iota(ord.begin(), ord.end(), 0);
merge_sort(ord);
output(ord);
} else {
vector<int> a{0, 1}, b{2, 3};
merge_sort(a);
merge_sort(b);
if (!cmp(a[0], b[0])) {
swap(a, b);
}
vector<int> c{a[0], b[0], b[1]};
int x = n - 1;
int lb = -1, ub = c.size();
while (ub - lb > 1) {
int mid = (lb + ub) / 2;
if (cmp(x, c[mid])) {
ub = mid;
} else {
lb = mid;
}
}
c.insert(c.begin() + ub, x);
lb = ub == 0, ub = c.size();
while (ub - lb > 1) {
int mid = (lb + ub) / 2;
if (cmp(a[1], c[mid])) {
ub = mid;
} else {
lb = mid;
}
}
c.insert(c.begin() + ub, a[1]);
output(c);
}
return 0;
}
归并排序 + 贪心 + 信息熵
n = 5 n=5 n=5 的情况,若不同二元组关系是独立的,可以贪心的将 5 ! 5! 5! 中排列不断地划分为合法集合与不合法集合,并使合法集合的最大值尽可能的小。即贪心的取信息熵最大的二元组进行询问。(关系不独立的情况下不确定正确性, 仅保证小数据集上通过测试)
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
auto cmp = [&](int a, int b) {
cout << "? " << char(a + 'A') << ' ' << char(b + 'A') << endl;
char c;
cin >> c;
return c == '<';
};
function<void(vector<int> &)> merge_sort = [&](vector<int> &a) {
int n = a.size();
if (n <= 1) {
return;
}
int m = n / 2;
vector<int> b(a.begin(), a.begin() + m);
vector<int> c(a.begin() + m, a.end());
merge_sort(b);
merge_sort(c);
for (int ai = 0, bi = 0, ci = 0; ai < n; ++ai) {
if (ci == (int)c.size() || (bi < (int)b.size() && cmp(b[bi], c[ci]))) {
a[ai] = b[bi++];
} else {
a[ai] = c[ci++];
}
}
};
int n, q;
cin >> n >> q;
auto output = [&](vector<int> &ord) {
cout << "! ";
for (int i : ord) {
cout << char(i + 'A');
}
cout << endl;
};
if (n == 26) {
vector<int> ord(n);
iota(ord.begin(), ord.end(), 0);
merge_sort(ord);
output(ord);
} else {
vector<vector<int>> g(n, vector<int>(n, -1));
auto judge = [&](vector<int> &a) {
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
if (g[a[i]][a[j]] == 0) {
return 0;
}
}
}
return 1;
};
for (;;) {
int c = 0;
vector<int> a(n);
iota(a.begin(), a.end(), 0);
vector<vector<int>> sat(n, vector<int>(n));
do {
if (judge(a)) {
c += 1;
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
sat[a[i]][a[j]] += 1;
}
}
}
} while (next_permutation(a.begin(), a.end()));
if (c == 1) {
iota(a.begin(), a.end(), 0);
do {
if (judge(a)) {
break;
}
} while (next_permutation(a.begin(), a.end()));
output(a);
break;
}
int qi = -1, qj = -1;
int mn = 0;
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
int d = abs(sat[i][j] - sat[j][i]);
if (qi == -1 || mn > d) {
qi = i, qj = j;
mn = d;
}
}
}
if (!cmp(qi, qj)) {
swap(qi, qj);
}
g[qi][qj] = 1;
g[qj][qi] = 0;
}
}
return 0;
}