#P14386. [JOISC 2017] 故障机器

    ID: 19417 远端评测题 1400ms 512MiB 尝试: 0 已通过: 0 显示难度省选/NOI− 上传者: 标签>2017交互题Special Judge期望线性基通信题JOISC/JOIST(日本)

[JOISC 2017] 故障机器

背景

本题仅允许使用 C++ 提交。因为需要较新版本的编译器,也请不要使用 C++14 (GCC 9)

洛谷不允许提交两个代码分别运行,所以需要你在提交时把代码合并。与原题不一样的是,你不需要提交两个文件,只需要实现题面中的两个函数。模板代码如下。

extern "C" void Set(int pos, int bit); // 只是一个声明,Set 不是你需要实现的函数
// 这里可以放你需要的头文件
// 这里可以放你需要的全局变量,注意 A 和 B 不共享这些变量,它们在不同的进程中运行
extern "C" void Anna(int N, long long X, int K, int P[]);
extern "C" long long Bruno(int N, int A[]);

保证若无非法操作,交互库占用内存小于 2MB,占用时间小于 450ms。

题目描述

这是一道通信题。

Anna 和 Bruno 是考古学家,他们正在伊朗调查遗迹。

他们的任务如下:Anna 前往遗迹并发现文物,Bruno 在大本营分析结果。

他们的调查计划持续 Q(=1000)Q(=1000) 天。每天,Anna 使用通信设备将结果发送给 Bruno。每天的结果以一个整数 XX 表示。

Anna 每天只能使用一次通信设备。它可发送一个长度为 N(=150)N(=150)、由 0 或 1 组成的序列。

然而,该设备已损坏。在长度为 NN 的序列中,存在若干损坏位置。对于损坏位置,无论实际设定值为何,设备总是发送值 0。当 Anna 发送序列时,她可以看到损坏位置的位置,但 Bruno 不知道这些位置。损坏位置的位置和数量每天都会变化。

存在调查可能被延误的危险。由于你是伊朗某国际编程竞赛的参赛者,Anna 和 Bruno 请求你编写一个程序,用于发送他们的调查结果。

任务

编写两个程序,以实现 Anna 和 Bruno 之间的通信:

  • 给定序列长度 NN、待发送的整数 XX、损坏位置数量 KK 以及损坏位置 PP,第一个程序设置 Anna 发送的序列 SS
  • 给定 Bruno 接收到的序列 AA,第二个程序恢复整数 XX

在通信设备正常工作的位置,序列 SS 与序列 AA 的值相同。在损坏位置,无论序列 SS 的值为何,序列 AA 总是值 0。

实现细节

你需要提交两个使用相同编程语言编写的文件。

第一个文件为 Anna.cAnna.cpp。该文件用于设置 Anna 发送的序列,并实现以下函数。程序中应包含 Annalib.h

  • void Anna( int N, long long X, int K, int P[] )

    对于每个测试用例,该函数将被调用 Q=1000Q = 1000 次。

    • 参数 NN 表示待发送序列的长度。
    • 参数 XX 是待发送的整数。
    • 参数 KK 是损坏位置的数量。
    • 参数 P[]P[] 是一个长度为 KK 的序列,描述损坏位置的位置。

在函数 Anna 中,必须调用以下函数:

  • void Set( int pos, int bit )

    该函数用于设置通信设备将要发送的序列 SS 中的某一位。

    • 参数 pos 是待设置位置的索引,其值必须是介于 0 到 N1N - 1(含)之间的整数。请注意,位置从 0 开始计数。若使用超出此范围的参数调用该函数,你的程序将被视为 Wrong Answer[1]。不允许使用相同的参数 pos 多次调用该函数;若发生此情况,你的程序将被视为 Wrong Answer[2]
    • 参数 bit 是设置到序列第 pos 位的值,其值必须为 0 或 1。若使用其他参数调用该函数,你的程序将被视为 Wrong Answer[3]

函数 Set 在函数 Anna 中必须被恰好调用 NN。当函数 Anna 结束时,若函数 Set 的调用次数与 NN 不一致,你的程序将被视为 Wrong Answer[4]

若函数 Anna 的调用被视为无效,你的程序将被终止。

第二个文件为 Bruno.cBruno.cpp。该文件用于恢复表示调查结果的整数,并实现以下函数。程序中应包含 Brunolib.h

  • long long Bruno( int N, int A[] )

    对于每个测试用例,该函数将被调用 Q=1000Q = 1000 次。

    • 参数 NN 是 Bruno 接收到的序列的长度。
    • 参数 AA 是一个长度为 NN 的整数序列,即 Bruno 接收到的序列。
    • 函数 Bruno 必须恢复出 XX 的值并返回它。

评分流程

评分按以下方式进行。若你的程序被视为 Wrong Answer,则立即被终止。

(1)设置 cnt = 0

(2)调用函数 Anna 一次。

(3)令 SS 为函数 Anna 设置的序列。在序列 SS 中,将位置 PP 上的值设为 0,得到序列 AA。以参数 AA 调用函数 Bruno 一次。

(4)设置 cnt=cnt+1cnt = cnt + 1。若 cnt<Qcnt < Q,返回步骤(2);若 cnt=Qcnt = Q,进入步骤(5)。

(5)你的程序将被评分。

重要提示

  • 运行时间和内存使用量将根据评分流程中的步骤(1)、(2)、(3)、(4)进行计算。
  • 你的程序在步骤(2)中调用函数 Anna 或在步骤(3)中调用函数 Bruno 时,不得被视为 Wrong Answer。你的程序必须在无运行时错误的情况下执行。
  • 你的程序可以为内部用途实现其他函数,或使用全局变量。提交的程序将与评分器一起编译,并生成一个单一的可执行文件。所有全局变量和内部函数应声明为 static,以避免与其他文件发生冲突。由于在评分时,Anna 和 Bruno 的程序将作为两个独立的进程执行,它们无法共享全局变量。
  • 在整个过程中,函数 AnnaBruno 各自将被调用 Q=1000Q = 1000 次。你的程序中使用的变量应被适当初始化。
  • 你的程序不应使用标准输入和标准输出。你的程序不得通过任何方式与其他文件通信。

编译与测试运行

你可以从竞赛网页下载一个归档文件,其中包含一个用于测试你程序的示例评分器。该归档文件还包含你程序的一个示例源代码文件。

示例评分器由一个源文件组成,该文件为 grader.cgrader.cpp。例如,若你的程序为 Anna.cBruno.c,或 Anna.cppBruno.cpp,则你可运行以下命令编译你的程序:

  • C
gcc -std=c11 -O2 -o grader grader.c Anna.c Bruno.c -lm
  • C++
g++ -std=c++14 -O2 -o grader grader.cpp Anna.cpp Bruno.cpp

当编译成功后,将生成可执行文件 grader

请注意,实际的评分器与示例评分器不同。示例评分器将以单个进程形式运行,它将从标准输入读取输入数据,并将结果写入标准输出。

输入格式

示例评分器从标准输入读取以下数据:

  • 第一行包含一个整数 QQ
  • 接着,给出 QQ 个查询的信息。
  • 每个查询的信息由两行组成,具体如下:
    • 第一行包含三个以空格分隔的整数 NNXXKK。这表示待发送序列的长度为 NN,Anna 要发送的整数为 XX,且有 KK 个损坏位置。
    • 第二行包含 KK 个以空格分隔的整数 P0,P1,,PK1P_0, P_1, \cdots, P_{K-1}。这意味着,对于每个 ii0iK10 \le i \le K - 1),序列中第 PiP_i 个位置是损坏的。

输出格式

当程序成功终止时,示例评分器将以下信息写入标准输出。(引号本身不会被实际输出。)

  • 若你的程序被视为 Wrong Answer,示例评分器将以如下格式输出其类型:“Wrong Answer [1]”,随后你的程序将被终止。
  • 若每次对函数 Anna 的调用均未被视为 Wrong Answer,示例评分器将输出 “Accepted” 及值 LL^*。关于 LL^* 的取值,请参见“评分”部分。

若你的程序被视为多种类型的 Wrong Answer,示例评分器仅报告其中一种。



提示

数据范围

所有输入数据均满足以下条件:

  • Q=1000Q = 1000
  • N=150N = 150
  • 0X10000000000000000000 \le X \le 1\,000\,000\,000\,000\,000\,000
  • 1K401 \le K \le 40
  • 0PiN10 \le P_i \le N - 10iK10 \le i \le K - 1)。
  • Pi<Pi+1P_i < P_{i+1}0iK20 \le i \le K - 2)。

评分

  • LL^* 为本题所有测试用例中以下值的最小值:

    • 满足条件的最大整数 L40L \le 40,使得对于每个满足 KLK \le L 的查询,Bruno 均能正确回答出 XX 的值。
  • 本题的得分按以下方式计算:

    • L=0L^* = 0,得分为 00 分。
    • 1L141 \le L^* \le 14,得分为 88 分。
    • 15L3715 \le L^* \le 37,得分为 (L15)×2+41(L^* - 15) \times 2 + 41 分。
    • 38L4038 \le L^* \le 40,得分为 (L38)×5+90(L^* - 38) \times 5 + 90 分。