#P5473. [NOI2019] I 君的探险

    ID: 4450 Type: RemoteJudge 2000ms 500MiB Tried: 0 Accepted: 0 Difficulty: 7 Uploaded By: Tags>2019NOI交互题Special JudgeO2优化

[NOI2019] I 君的探险

题目背景

附加文件可在页面底部「附件」中下载。

特别提示

在洛谷提交本题时的一些注意事项(与原题面不同之处请以此处为准):

  1. 与原题不同的是,你不需要,也不应该在程序开头包含 explore.h 头文件。

  2. 为了确保程序正常编译,你需要在你提交的程序开头加上如下函数声明语句:

void modify(int x);
int query(int x);
void report(int x, int y);
int check(int x);
  1. 本题仅支持 C++ 语言(包括 C++C++11C++14C++17)提交。

题目描述

时隔半年,I 君的商店终于开不下去了,他决定转让商店,做一名探险家去探索未知的广阔世界。

根据古书记载,他在一个大荒漠的腹地找到了未知文明创造的地下宫殿,宫殿由 NN 个大型洞穴和 MM 条连接这些洞穴的双向通路构成。I 君能借助古书分辨所处的洞穴,但书中并没有记录 MM 条通路的连接结构,因此他难以搜寻传说中藏在宫殿里的无尽财宝。

不过现在 I 君发现了一个神秘机关,通过它可以获知宫殿的信息,I 君决定利用这个机关来得到宫殿的连接结构,请你来协助他。

地下宫殿可以抽象成一张 NN 个点、MM 条边的无向简单图(简单图满足任意两点之间至多存在一条直接相连的边),洞穴从 0n10 \sim n - 1 编号。目前你并不知道边有哪些。

每个洞穴都拥有一个光源,光源有开启、关闭两种状态,只有当光源处于开启状态时它所在的洞穴才会被照亮。初始时所有的光源都处于关闭状态,而光源的状态只能用I 君发现的神秘机关改变。更具体的,使用神秘机关可以进行如下四种操作:

  1. 向机关给定一个编号 xx,机关将会改变xx 号洞穴,以及与xx 号洞穴有通路直接相连的洞穴的光源状态。即原来开启的光源将会关闭;原来关闭的光源将会开启。

  2. 向机关给定一个编号 xx,机关将会显示当前xx 号洞穴光源的状态。

  3. 向机关给定两个编号 x,yx, y,表示你确定有一条连接 xx 号洞穴与 yy 号洞穴的通路,并让机关记录。

  4. 向机关给定一个编号 xx,机关将会判断与 xx 号洞穴相连的通路是否都已被记录。

机关在完成上一次操作后才能进行下一次操作。机关不能随意使用,因此每种操作的使用次数都有限制,分别为 Lm,Lq,M,LcL_m, L_q, M, L_c。你的任务是,编写一个程序,帮助 I 君决定如何合理利用神秘机关,从而正确地找到这 MM 条通路。

实现细节

你不需要,也不应该实现主函数,你只需要实现函数 explore(N, M),这里的 NNMM 分别表示洞穴和通路的个数。你可以通过调用如下四个函数来和交互库进行交互:

  1. modify(x)
  • 这个函数可以令机关执行操作 11,给定的编号为 xx

  • 你需要保证 0x<N0 \leq x < N,这个函数没有返回值。

  1. query(x)
  • 这个函数可以令机关执行操作 22,给定的编号为 xx

  • 你需要保证 0x<N0 \leq x < N,这个函数返回 0011,表示目前 xx 号洞穴的光源为关闭(00 表示)或开启(11 表示)状态。

  1. report(x, y)
  • 这个函数可以令机关执行操作 33,给定的编号为 x,yx, y

  • 你需要保证 0x,y<N0 \leq x, y < Nxyx \neq y,这个函数没有返回值。

  1. check(x)
  • 这个函数可以令机关执行操作 44,给定的编号为 xx

  • 你需要保证 0x<N0 \leq x < N,这个函数返回 0011,其中返回 11 当且仅当与 xx 号洞穴相连的所有通路都已通过操作 3 被记录。

评测时,交互库会恰好调用 explore 一次。

本题保证所使用的图在交互开始之前已经完全确定,不会根据和你的程序的交互过程动态构造,因此题目中的交互操作都是确定性的,你不需要关心这些操作在交互库中的具体实现。

数据保证在调用次数限制下,交互库运行所需的时间不超过1s;交互库使用的内存大小固定,且不超过128MB。

实现方法

选手工作目录下已经提供了一个 template_explore.cpp/c/pas,请将这个文件拷贝一份,重命名为 explore.cpp/c/pas,然后在其基础上答题。

  1. 对 C++ / C 语言选手
  • 请确保你的程序开头有
#include "explore.h"。
  • 你需要实现的函数 explore 的接口信息如下:
void explore(int N, int M);
  • 你可以调用的交互函数的接口如下:
void modify(int x);
int query(int x);
void report(int x, int y);
int check(int x);
  1. 对 Pascal 语言选手
  • 注意:Pascal 的代码中实现接口的语法较为复杂,请选手直接在下发的. template_explore.pas 的基础上进行答题,而不是自己从头实现代码。

  • 你需要实现的函数 explore 的接口信息如下:

procedure _explore(N, M : longint);
  • 注意:这里的函数名称是_explore 而非explore,如果使用explore 将导致编译失败。

  • 你可以调用的交互函数的接口如下:

procedure modify(x : longint);
function query(x : longint) : longint;
procedure report(x : longint; y : longint);
function check(x : longint) : longint;

试题目录下的 grader.cpp/c 以及 graderhelperlib.pas 是我们提供的交互库参考实现,最终测试时所用的交互库实现与该参考实现有所不同,因此选手的解法不应该依赖交互库实现。

  1. C/C++ 语言的选手:
  • 你需要在本题目录下使用如下命令编译得到可执行程序:

  • 对于 C 语言:

gcc grader.c explore.c -o explore -O2 -lm
  • 对于 C++ 语言:
g++ grader.cpp explore.cpp -o explore -O2 -lm
  1. 对于 Pascal 语言的选手:
  • 你需要在本题目录下使用如下命令编译得到可执行程序:
fpc grader.pas -o"explore" -O2
  1. 对于编译得到的可执行程序:
  • 可执行文件将从标准输入读入以下格式的数据:

第一行包含三个整数 Lm,Lq,LcL_m, L_q, L_c ,第二行包含两个整数 N,MN, M,意义如题面描述。

接下来 MM 行,每行两个整数 x,yx, y,描述一条连接 xx 号洞穴与 yy 号洞穴的通路。

  • 读入完成之后,交互库将调用恰好一次函数 explore,用输入的数据测试你的函数。你的函数正确返回后,交互库会判断你的计算是否正确,若正确则会输出 Correct 和交互函数调用次数相关信息,否则会输出相应的错误信息。
100 200 300
3 2
0 1
1 2

见“提示与说明”

提示

数据第一行的三个整数分别表示三种操作的调用次数限制,即 modify(x) 调用次数不能超过 100100query(x) 调用次数不能超过 200200check(x) 调用次数不能超过 300300

数据第二行的两个整数分别表示洞穴数和通路条数,即 N=3,M=2N = 3 , M = 2

report(x, y) 调用次数不能超过 MM,该例子中即不超过 22 次。

下面是一个正确的交互过程:

选手程序 交互库 说明
调用 explore(3,2)\text{explore}(3,2) 开始测试
调用 modify(0)\text{modify}(0) 00 号洞穴做操作 11
调用 query(2)\text{query}(2) 返回 00 目前 22 号洞穴的光源状态是关闭
调用 report(0,1)\text{report}(0,1) 发现了道路 (0,1)(0,1) 并记录
调用 check(0)\text{check}(0) 返回 11 00 号洞穴相关的道路都已被记录
调用 report(2,1)\text{report}(2,1) 发现了道路 (2,1)(2,1) 并记录
运行结束并返回 向屏幕打印 Correct\text{Correct} 交互结束,结果正确

下发文件说明

在本试题目录下:

  1. grader.cpp/c 以及 graderhelperlib.pas 是我们提供的交互库参考实现。

  2. explore.hgrader.pas 是头文件,选手不用关心具体内容。

  3. template_explore.cpp/c/pas 是我们提供的样例解题源代码。

  4. explore1.inexplore2.inexplore3.in 是样例输入,可供测试。

选手注意对所有下发文件做好备份。评测只收取本试题目录下的explore.c/cpp/pas,并且对该程序以外的文件的修改无效。

最终评测只会收取 explore.cpp/c/pas,修改选手目录下其他文件对评测无效。

本题首先会受到和传统题相同的限制。例如编译错误会导致整道题目得 00 分,运行时错误、超过时间限制、超过空间限制等会导致相应测试点得 00 分等。你只能访问自己定义的和交互库给出的变量及其对应的内存空间,尝试访问其他空间将可能导致编译错误或运行错误。

在上述条件基础上,在一个测试点中,你得到满分,当且仅当:

  1. 你的每次函数调用均合法,且调用 modifyquerycheck 的次数分别不超过Lm,Lq,LcL_m, L_q, L_c

  2. 由于 report 的调用次数限制为 MM,你的每次调用都必须记录一条新的且存在的边;即每次调用 report(x, y) 时,应满足:有一条连接 xx 号洞穴和 yy 号洞穴的通路,且在这次调用之前从未调用过 report(x, y)report(y, x)

  3. 你实现的函数 explore 正常返回。

  4. explore 函数返回时,你已经通过调用 report 记录了全部 MM 条通路。

本题共 2525 个测试点,每个测试点 44 分。每个测试点的数据规模和相关限制见下表。 | 测试点编号 | N=N= | M=M= | Lm=L_m= | Lq=L_q= | Lc=L_c= | 特殊性质 | | :----------: | :----------: | :----------: | :----------: | :----------: | :----------: | :----------: | | 11 | 33 | 22 | 100100 | 100100 | 100100 | 无 | | 22 | 100100 | 10×N10\times N | 200200 | 10410^4 | 2×M2\times M | 无 | | 33 | 200200 | 10×N10\times N | 200200 | 4×1044\times 10^4 | 2×M2\times M | 无 | | 44 | 300300 | 10×N10\times N |299299 | 9×1049\times 10^4 | 2×M2\times M | 无 | | 55 | 500500 | 10×N10\times N | 499499 | 1.5×1051.5\times 10^5 | 2×M2\times M | 无 | | 66 | 5999859998 | N2\frac{N}{2} | 17×N17\times N | 17×N17\times N | 00 | AA | | 77 | 9999899998 | N2\frac{N}{2} | 18×N18\times N | 18×N18\times N | 00 | AA | | 88 | 199998199998 | N2\frac{N}{2} | 19×N19\times N | 19×N19\times N | 00 | AA | | 99 | 199998199998 | N2\frac{N}{2} | 19×N19\times N | 19×N19\times N | 00 | AA | | 1010 | 9999799997 | N1N-1 | 18×N18\times N | 18×N18\times N | 00 | BB | | 1111 | 199997199997 | N1N-1 | 19×N19\times N | 19×N19\times N | 00 | BB | | 1212 | 9999699996 | N1N-1 | 10710^7 | 10710^7 | 2×M2\times M | CC | | 1313 | 199996199996 | N1N-1 | 10710^7 | 10710^7 | 2×M2\times M | CC | | 1414 | 199996199996 | N1N-1 | 10710^7 | 10710^7 | 2×M2\times M | CC | | 1515 | 9999599995 | N1N-1 | 10710^7 | 10710^7 | 2×M2\times M | DD | | 1616 | 9999599995 | N1N-1 | 10710^7 | 10710^7 | 2×M2\times M | DD | | 1717 | 199995199995 | N1N-1 | 10710^7 | 10710^7 | 2×M2\times M | DD | | 1818 | 10041004 | 2×1032\times 10^3 | 10710^7 | 5×1045\times 10^4 | 2×M2\times M | 无 | | 1919 | 10041004 | 3×1033\times 10^3 | 10710^7 | 5×1045\times 10^4 | 2×M2\times M | 无 | | 2020 | 10041004 | 3×1033\times 10^3 | 10710^7 | 5×1045\times 10^4 | 2×M2\times M | 无 | | 2121 | 5×1045\times 10^4 | 2×N2\times N | 10710^7 | 10710^7 | 2×M2\times M | 无| | 2222 | 10510^5 | 2×N2\times N | 10710^7 | 10710^7 | 2×M2\times M | 无 | | 2323 | 1.5×1051.5\times 10^5 | 2×1052\times 10^5 | 10710^7 | 10710^7 | 2×M2\times M | 无 | | 2424 | 2×1052\times 10^5 | 2.5×1052.5\times 10^5 | 10710^7 | 10710^7 | 2×M2\times M | 无 | | 2525 | 2×1052\times 10^5 | 3×1053\times 10^5 | 10710^7 | 10710^7 | 2×M2\times M | 无 |

再次提醒,题目保证测试所使用的图在交互开始之前已经完全确定,而不会根据和你的程序的交互动态构造。

表中特殊性质栏中变量的含义如下:

A:保证每个点的度数恰好为 11

B:保证对于每个 x>0x > 0,存在恰好一个 y<xy < xyy 使得 xx 号洞穴与 yy 号洞穴有通路直接相连。

C:存在 0N10 \sim N - 1 的一个排列 p0,p1,,pN1p_0, p_1, \cdots , p_{N-1},使得对任意 1i<N1 \leq i < N,存在一条连接洞穴编号分别为 pi1p_{i-1}pip_i 的通路。

D:保证图连通。

  • 提示:你的程序可以通过判断传入的 NN 的个位来区分上述不同的数据类型。