你刚刚从监狱中逃脱,结束了你作为艺术大盗的灾难性首秀。看来,走合法途径进入艺术行业是个更好的主意。于是,你决定在你之前被捕的那家博物馆担任艺术评论家。
这意味着你需要多次参观博物馆,并为每次参观撰写一份艺术评论。一份艺术评论涵盖博物馆中的几对房间。在每次参观期间,你会比较两个房间的艺术品,并确定哪个房间展示的艺术收藏品具有更高的审美价值*。最终,你还希望对博物馆内的所有艺术品进行调查。也就是说,利用你所有的评论,你希望按照艺术收藏品审美价值递减的顺序,对博物馆内的所有房间进行排名。
由于规划是关键,你决定提前为每次参观选定要比较的房间对。此外,为了多样性,在单次艺术评论中,同一个房间不能出现超过一次。
不幸的是,你在艺术界新获得的声誉成了障碍。每当你宣布在下次参观时要比较某一对房间时,博物馆可能会自发地交换这两个房间的艺术收藏品。你最终的调查和房间排名应该基于你最后一次参观时每个房间展示的内容。
编写一个程序,安排不超过 $V$ 次博物馆参观,并根据由此产生的艺术评论,计算出博物馆所有房间的列表,按最后一次参观时各房间展示的艺术收藏品审美价值递减的顺序排列。
交互
这是一个交互式任务。你必须实现函数 void solve(int N, int V),其中 $N$ 是博物馆的房间数量(编号为 1 到 $N$),$V$ 是你被允许进行的最大参观次数。对于每个测试用例,该函数会被调用且仅被调用一次。在函数中,你可以使用评测系统提供的以下其他函数:
void schedule(int i, int j):安排在下次参观时比较房间 $i$ 和 $j$($1 \le i, j \le N, i \neq j$)。在调用此函数后,博物馆可能会立即决定交换房间 $i$ 和 $j$ 的艺术收藏品。vector<int> visit():参观博物馆并执行所有已安排的比较。此函数返回一个数组,其中包含自上次参观博物馆(即自上次调用visit或程序开始以来,每次调用schedule)以来,每次已安排比较的结果。如果第 $k+1$ 次安排的比较中,房间 $i$ 的艺术品审美价值高于房间 $j$,则数组中对应索引处的条目为 1,否则为 0。void answer(vector<int> r):发布你按审美价值递减顺序排列的博物馆所有房间列表。$r$ 必须是一个长度为 $N$ 的数组;其第 $k$ 个条目是最后一次参观时审美价值第 $k+1$ 高的房间。你必须调用answer恰好一次;你的程序随后会自动终止。
如果你的任何函数调用不符合上述格式,如果在两次 visit 调用之间多次将同一个房间作为参数传递给 schedule,或者如果你调用 visit 的次数超过了 $V$ 次,你的程序将立即终止,并被判定为该测试用例的“不正确”(Not correct)。你不得向标准输出写入任何内容,否则你可能会收到“安全违规”(Security violation!)的判决。
- 当然,任何对艺术的评价都只能是相对的。这就是为什么在参观之后,你只能知道每对比较过的房间的相对顺序,而无法得知处于不同比较对中的已参观房间之间的顺序。
数据范围
我们始终有 $1 \le N \le 500$ 且 $50 \le V \le 5\,000$。
- 子任务 1(5 分):$V = 5\,000$,博物馆从不交换艺术收藏品。
- 子任务 2(10 分):$V \ge 1\,000$,博物馆从不交换艺术收藏品。
- 子任务 3(5 分):$N \le 100, V = 5\,000$。
- 子任务 4(15 分):$V = 5\,000$。
- 子任务 5(15 分):$V \ge 500$。
- 子任务 6(35 分):$V \ge 100$。
- 子任务 7(15 分):$V \ge 50$。
此外,以下条件成立:在子任务 3 到 7 的每一个中,如果你解决了博物馆在每次调用 schedule 时总是将审美价值较高的艺术收藏品放入房间 $i$ 的所有测试用例,你将获得该子任务分数的 60%。在 CMS 中,这显示为相应子任务的“Group 1”。
注意:在 QOJ 中,每个子任务中的测试组被拆分为单独的子任务。也就是说,总共有 13 个子任务(子任务 #1 将是样例)。
样例
考虑一个 $N = 4$ 且 $V = 50$ 的测试用例,最初房间按审美价值递减顺序排列为 1, 2, 3, 4。开始时,评测系统调用你的函数 solve(4, 50)。然后,你的程序与评测系统之间的一种可能的交互如下:
| 你的程序 | 返回值 | 说明 |
|---|---|---|
schedule(1, 2) |
安排比较房间 1 和 2 的艺术品 | |
schedule(3, 4) |
安排比较房间 3 和 4 的艺术品 | |
| 博物馆交换了房间 3 和 4 的艺术品 | ||
visit() |
{1, 0} |
参观博物馆并执行所有比较;房间 1 的艺术品价值高于房间 2,房间 4 的艺术品价值高于房间 3 |
schedule(2, 4) |
安排比较房间 2 和 4 的艺术品 | |
visit() |
{1} |
参观博物馆;房间 2 的艺术品价值高于房间 4 |
answer({1, 2, 4, 3}) |
你确信房间按审美价值递减顺序为 1, 2, 4, 3;该解法正确并被接受 |
注意,上述查询当然不足以确定房间的顺序:例如,顺序 2, 1, 4, 3 也与所有 visit 的回答一致。这个顺序是在从 4, 1, 2, 3 开始,并在最后一次调用 schedule 后交换房间 2 和 4 的艺术品时获得的。
实现细节
如果你使用 C++,必须在源代码中包含 swaps.h。为了在本地测试你的程序,你可以将你的程序与 sample_grader.cpp 链接,该文件可以在 CMS 的任务附件中找到(下文有关于样例评测程序的描述)。附件中还包含一个带有额外说明的样例实现 swaps_sample.cpp。
如果你使用 Python,可以在附件中找到样例实现 swaps_sample.py,其中也描述了 Python 提交的接口。
评测程序
样例评测程序在标准输入中期望得到数字 $N$ 和 $V$,以及 $N$ 个整数,即在 solve 开始时按审美价值递减顺序排列的房间。然后,评测程序向标准输出写入你程序调用的所有评测函数的协议。每当调用 schedule(i, j) 时,评测程序在标准输入中期望得到数字 1(如果此时应交换房间 $i$ 和 $j$ 的艺术收藏品)或 0。最后,评测程序向标准输出写入以下消息之一:
Invalid input.:通过标准输入提供给评测程序的输入不符合上述格式。Invalid schedule.:调用schedule函数时参数无效。Out of visits.:调用visit函数的次数超过了 $V$ 次。Invalid answer.:调用answer函数时参数无效。Wrong answer.:调用answer函数时传入了错误的房间列表。No answer.:solve函数在未调用answer的情况下终止。Correct: v visit(s) used.:未发生上述任何情况,且visit函数被调用了 $v$ 次。
相比之下,用于评估你提交代码的评测程序只会输出 Not correct(针对上述任何错误)或 Correct。无论是在样例评测程序还是用于评估的评测程序中,只要发生上述任何错误,或者如果你的程序调用了 answer,程序都会自动终止。