#P14392. [JOISC 2017] 都市 / City

    ID: 20112 远端评测题 3000ms 250MiB 尝试: 0 已通过: 0 显示难度NOI/NOI+/CTS 上传者: 标签>2017交互题Special Judge通信题JOISC/JOIST(日本)

[JOISC 2017] 都市 / City

背景

评测说明(请仔细阅读)

  1. 不要 #include{\texttt{\#include}}。
  2. 请使用 C++20\red{\texttt{C++20}}。
  3. 在文件头粘贴如下的内容:
void Code(int city, long long code);

题目描述

JOI 王国内有许多城市。道路网络满足以下条件:

  • (条件 1)城市编号从 00 到 N−1N - 1。其中,NN 是 JOI 王国内的城市总数。
  • (条件 2)城市之间由 N−1N - 1 条道路连接。每条道路均可双向通行,且通过若干条道路,可以从任意城市到达其他任意城市。
  • (条件 3)从城市 00 出发,最多经过 1818 条道路即可到达任意其他城市。

每天,在 JOI 王国,许多人从城市 00 出发前往其他城市。由于许多人有两个目的地,他们有时会提出以下查询:对于两个不同的城市 XX、YY,以下哪一项(00)、(11)、(22)成立?

  • (00)当我们从城市 00 前往城市 XX 时,必定会经过城市 YY。
  • (11)当我们从城市 00 前往城市 YY 时,必定会经过城市 XX。
  • (22)以上两项(00)和(11)均不成立。

注意,在上述情形中,(00)、(11)、(22)中恰好有一项成立。当 X=0X = 0 时,无论 YY 取何值,我们均认为(11)成立;类似地,当 Y=0Y = 0 时,无论 XX 取何值,我们均认为(00)成立。

已知,正如 JOI 王国的道路网络一样,上述条件 1–3 在其他国家也成立。在 JOI 王国,人们计划开发以下两台机器,以便它们也可在其他国家使用:

  • (机器 1)给定城市数量 NN 和道路网络信息,该机器为每个城市分配一个编码。编码是一个介于 00 到 260−12^{60} - 1(含)之间的整数。
  • (机器 2)给定由机器 1 分配的两个不同城市 XX、YY 的编码,该机器回答查询。

若分配的编码为大整数,则处理起来较为困难。我们希望开发的机器能分配较小的值作为编码。

注意,当使用机器 2 时,城市数量 NN 和道路网络信息不会直接提供给机器。

任务

为了开发上述两台机器,请编写以下两个程序:

  • 给定 JOI 王国内的城市数量 NN 和道路网络信息,第一个程序为每个城市分配一个编码。
  • 给定由第一个程序分配的两个不同城市的编码,第二个程序回答针对这些城市的查询。

实现细节

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

第一个文件为 Encoder.c 或 Encoder.cpp,该文件实现机器 1。它应实现以下函数,并且程序应包含 Encoder.h。

  • void Encode(int N, int A[], int B[])

    对于每个测试用例,该函数被调用一次。

    • 参数 NN 表示城市数量。
    • 参数 A[]A[]、B[]B[] 是长度为 N−1N - 1 的整数序列,用于描述道路网络。元素 A[i]A[i]、B[i]B[i](0≤i≤N−20 \le i \le N - 2)表示城市 A[i]A[i] 与城市 B[i]B[i] 之间有一条直接相连的道路。

你的程序应调用以下函数:

  • void Code(int city, long long code)

    该函数为城市分配编码。

    • 参数 city 是被分配编码的城市编号,其值应为介于 00 到 N−1N - 1(含)之间的整数。若调用该函数时参数超出此范围,你的程序将被判定为 Wrong Answer[1]。若使用相同的参数调用该函数两次,你的程序将被判定为 Wrong Answer[2]。
    • 参数 code 是分配给编号为 city 的城市的编码,其值应为介于 00 到 260−12^{60} - 1(含)之间的整数。若调用该函数时参数超出此范围,你的程序将被判定为 Wrong Answer[3]。

你的程序应恰好调用函数 Code NN 次。若函数 Encode 结束时调用 Code 的次数不为 NN,你的程序将被判定为 Wrong Answer[4]。

若对函数 Encode 的调用被判定为错误答案,你的程序将立即终止。

第二个文件为 Device.c 或 Device.cpp,该文件实现机器 2。它应实现以下函数,且程序应包含 Device.h。

  • void InitDevice()

    该函数初始化机器 2。函数 InitDevice 在调用以下函数 Answer 之前被调用一次。

  • int Answer(long long S, long long T)

    该函数回答每个查询。对于每个查询,函数 Answer 被调用一次。

    • 参数 SS、TT 是由函数 Encode 分配给两个不同城市 XX、YY 的编码。

    • 为回答查询,函数 Answer 的返回值应满足以下条件:

      • 若从城市 00 前往城市 XX 时必定经过城市 YY,则返回值应为 00。
      • 若从城市 00 前往城市 YY 时必定经过城市 XX,则返回值应为 11。
      • 否则,返回值应为 22。

    因此,函数 Answer 的返回值应为介于 00 到 22(含)之间的整数。若返回值超出此范围,你的程序将被判定为 Wrong Answer[5]。若返回值在此范围内但不满足上述条件,你的程序将被判定为 Wrong Answer[6]。

评分流程

评分按以下方式进行。若你的程序被判定为错误答案,则立即终止。

(1)函数 Encode 被调用一次。

(2)函数 InitDevice 被调用一次。

(3)对于每个测试用例,机器 2 会收到 QQ 个查询。对于第 jj 个查询(1≤j≤Q1 \le j \le Q),函数 Answer 被调用,其参数 SS 为 SjS_j,参数 TT 为 TjT_j,其中 SjS_j、TjT_j 分别是由函数 Encode 分配给城市 XjX_j、YjY_j 的编码。

(4)你的程序被视为正确。

重要提示

  • 运行时间和内存使用量根据评分流程中的(1)、(2)、(3)计算。注意,在流程(3)中,函数 Answer 总共被调用 QQ 次。
  • 你的程序在流程(1)中调用函数 Encode、在流程(2)中调用函数 InitDevice、或在流程(3)中调用函数 Answer 时,均不得被判定为 Wrong Answer。你的程序必须在无运行时错误的情况下执行。
  • 你的程序可以为内部使用实现其他函数,或使用全局变量。提交的程序将与评分器一起编译,并生成一个可执行文件。所有全局变量和内部函数应声明为 static,以避免与其他文件发生冲突。机器 1 和机器 2 的程序在评分时将作为两个独立的进程运行,它们不能共享全局变量。
  • 你的程序不应使用标准输入和标准输出。你的程序不得通过任何方式与其他文件通信。

编译与测试运行

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

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

  • C

    gcc -std=c11 -O2 -o grader grader.c Encoder.c Device.c -lm

  • C++

    g++ -std=c++14 -O2 -o grader grader.cpp Encoder.cpp Device.cpp

当编译成功后,将生成可执行文件 grader。注意,实际评分器与示例评分器不同。示例评分器将以单个进程形式运行,它将从标准输入读取输入数据,并将结果写入标准输出。

输入格式

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

  • 第一行包含两个以空格分隔的整数 NN、QQ。这表示共有 NN 个城市,以及给出 QQ 个查询。
  • 接下来的 N−1N - 1 行中,第 (i+1)(i + 1) 行(0≤i≤N−20 \le i \le N - 2)包含两个以空格分隔的整数 AiA_i、BiB_i。这表示城市 AiA_i 与城市 BiB_i 之间有一条直接相连的道路。
  • 接下来的 QQ 行中,第 jj 行(1≤j≤Q1 \le j \le Q)包含三个以空格分隔的整数 XjX_j、YjY_j、EjE_j。这表示在第 jj 个查询中,X=XjX = X_j 且 Y=YjY = Y_j;若你的程序对该查询的回答与 EjE_j 不同,示例评分器将判定你的程序为 Wrong Answer。

输出格式

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

  • 若你的程序被视为正确,示例评分器将以如下格式输出所分配编码的最大值:“Accepted : max_code=123456”。
  • 若你的程序被视为错误答案,示例评分器将以如下格式输出其错误类型:“Wrong Answer [1]”。

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

6 5
4 1
0 3
4 5
3 2
3 4
2 4 2
1 0 0
5 1 2
5 3 0
4 1 1

提示

样例 1 解释

函数 Encode(...) 将使用以下参数被调用:

参数 Encode(...)
NN 66
AA {4,0,4,3,3}\{4, 0, 4, 3, 3\}
BB {1,3,5,2,4}\{1, 3, 5, 2, 4\}
Machine 1 Machine 2
Encode(...)
Code(0,0)
Code(2,4)
Code(4,16)
Code(1,1)
Code(3,9)
Code(5,25)
InitDevice()
Answer(4,16)
Answer(1,0)
Answer(25,1)
Answer(25,9)
Answer(16,1)

数据范围

所有输入数据满足以下条件。关于 NN、QQ、AiA_i、BiB_i、XjX_j、YjY_j 的含义,请参见“示例评分器的输入”。

  • 2≤N≤2500002 \le N \le 250000。
  • 1≤Q≤2500001 \le Q \le 250000。
  • 0≤Ai≤N−10 \le A_i \le N - 1(0≤i≤N−20 \le i \le N - 2)。
  • 0≤Bi≤N−10 \le B_i \le N - 1(0≤i≤N−20 \le i \le N - 2)。
  • Ai≠BiA_i \ne B_i(0≤i≤N−20 \le i \le N - 2)。
  • 从城市 00 出发,最多经过 1818 条道路即可到达任意其他城市。
  • 0≤Xj≤N−10 \le X_j \le N - 1(1≤j≤Q1 \le j \le Q)。
  • 0≤Yj≤N−10 \le Y_j \le N - 1(1≤j≤Q1 \le j \le Q)。
  • Xj≠YjX_j \ne Y_j(1≤j≤Q1 \le j \le Q)。

子任务

共有 2 个子任务。每个子任务的得分及额外约束如下:

子任务 1 [8 分]

  • N≤10N \le 10。

子任务 2 [92 分]

无额外约束。在本子任务中,得分按如下方式计算:

  • 设 LL 为本子任务所有测试用例中分配给城市的编码的最大值。

  • 本子任务的得分为:

    • 若 238≤L2^{38} \le L,得 00 分。
    • 若 236≤L≤238−12^{36} \le L \le 2^{38} - 1,得 1010 分。
    • 若 235≤L≤236−12^{35} \le L \le 2^{36} - 1,得 1414 分。
    • 若 234≤L≤235−12^{34} \le L \le 2^{35} - 1,得 2222 分。
    • 若 228≤L≤234−12^{28} \le L \le 2^{34} - 1,得 ⌊372−10log⁡2(L+1)⌋\lfloor 372 - 10 \log_2(L + 1) \rfloor 分。其中,⌊x⌋\lfloor x \rfloor 表示不超过 xx 的最大整数。
    • 若 L≤228−1L \le 2^{28} - 1,得 9292 分。

请注意,若 238≤L2^{38} \le L,本子任务的结果在竞赛系统中可能显示为“Accepted : 0 points”或“Wrong Answer”。

翻译由 Qwen3-235B 完成