题目大意:
今年是 3345 年,你打算还原千年前这场比赛的名次,但是主办方称由于技术原因排名遗失了,连
用于排名的 a 也丢失了。所幸,在 Byteland 中生活的都是机器人,所以你可以询问这些千年前的参赛
选手。为了谨慎起见,你可以每次询问一个参赛者,某一个参赛者的比赛成绩比它好还是比它差。但是,
机械心理学家告诉你,这些选手不一定愿意回答你的提问。具体地:
- 名次小于 1 的选手由于耿耿于怀,如果它应该回答另一个参赛者成绩比它好,它就会选择不回答,
否则它会如实回答。 - 名次为 1 的选手决定闷声大发财,它无论如何都不会回答任何提问。
- 名次为 2 的选手只当询问排名为 3 的选手时才回答比排名 3 的好,其他时候都不回答。
- 名次为 3 的选手趾高气扬,如果它应该回答另一个参赛者成绩比它好,它就会选择不回答,否则
它会如实回答。 - 名次大于 3 的选手感觉自己水平不行,如果它应该回答另一个参赛者成绩比它差,它就会选择不
回答,否则它会如实回答。
你希望通过一些询问还原每个选手的名次,询问数越少你的得分越高,评分细则请看 Notes 一节。
4 ≤ n ≤ 1000,数据保证名次由一个 a < 1 生成,且存在名次为 1, 2, 3 的选手。
本题有若干个测试点,你本题的得分是每个测试点的得分的最小值。
对于某个测试点,若你没有正确还原出每个选手的名次,该测试点得 0 分。
否则设你使用了 x 个询问,设 y = {11500, 12000, 13000, 14000, 15000, 16000, 17000, 18000, 19000, 21000},
若 y 中有 a 个大于等于 x 的元素,则该测试点得 10a 分。
题解:
做得太少了还是没有经验。
不难想到将序列分成两个部分,然后分开排序。
排序的话复杂度为 O ( n l o g n ) O(n~log~n) O(n log n),使用插入排序可以获得9000次左右的快乐。
那如何分成两个部分,注意回答比自己高的只有 > 3 >3 >3的。
那么不妨扫过去的时候记录最小值,出现过比自己高的就是 > 3 >3 >3的。
这一部分复杂度是 O ( 2 n ) O(2n) O(2n)
然后 < = 3 <=3 <=3的一起排,你会发现排完之后 1 、 2 、 3 1、2、3 1、2、3就在序列的末端,但是无法确定顺序,再用至多六次即可判断出位置。
Code:
#include "rank.hpp"
#include<ctime>
#include<algorithm>
#define pp printf
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define fd(i ,x, y) for(int i = x, B = y; i >= B; i --)
using namespace std;
const int N = 1e3 + 5;
int ak[N][N];
int zz(int x, int y) {
if(ak[x][y] >= 0) return ak[x][y];
char c = ask(x - 1, y - 1);
return ak[x][y] = (c == 'n' ? 0 : (c == 'g' ? 1 : 2));
}
int ans[N];
const int inf = 1e9;
int p[N], q[N], bz[N];
int c1(int x, int y) {
return zz(x, y);
}
int c2(int x, int y) {
return !zz(x, y);
}
int b[N];
void sort(int *p, int (*cmp)(int x, int y)) {
fo(i, 1, p[0]) {
int as = 0;
for(int l = 1, r = i - 1; l <= r; ) {
int mi = l + r >> 1;
if(cmp(b[mi], p[i])) as = mi, l = mi + 1; else r = mi - 1;
}
fd(j, i, as + 2) b[j] = b[j - 1];
b[as + 1] = p[i];
}
fo(i, 1, p[0]) p[i] = b[i];
}
vector<int> work(int n)
{
vector<int> V;
fo(i, 1, n) fo(j, 1, n) ak[i][j] = -1;
fo(i, 1, n) ans[i] = inf;
int x = 1;
fo(i, 2, n) {
int u = zz(x, i), v = zz(i, x);
if(u == 1) bz[x] = 1;
if(v == 1) bz[i] = 1;
if(u == 1 || v == 2) x = i;
}
fo(i, 1, n) if(bz[i]) q[++ q[0]] = i; else p[++ p[0]] = i;
sort(p, c1); sort(q, c2);
int u, v;
fo(i, p[0] - 2, p[0]) fo(j, p[0] - 2, p[0]) if(i != j)
if(c1(p[i], p[j])) { u = p[i], v = p[j]; fo(k, p[0] - 2, p[0]) if(k != i && k != j) x = p[k]; break;}
ans[x] = 1; ans[u] = 2; ans[v] = 3;
fd(i, p[0] - 3, 1) ans[p[i]] = 3 - (p[0] - i);
fo(i, 1, q[0]) ans[q[i]] = 3 + i;
fo(i, 1, n) V.push_back(ans[i]);
return V;
}