#P12867. [JOI Open 2025] 心灵感应 / Telepathy

    ID: 14708 远端评测题 2500ms 1024MiB 尝试: 0 已通过: 0 显示难度NOI/NOI+/CTS 上传者: 标签>2025交互题Special JudgeJOI(日本)通信题

[JOI Open 2025] 心灵感应 / Telepathy

背景

译自 JOI Open 2025 T3「Telepathy」/ 「テレパシー」。

这是一道通信题。请使用 C++ 20\texttt{\textcolor{red}{C++\,20}} 提交。

不要 #include "telepathy.h"\texttt{\#include "telepathy.h"}。

题目描述

这是一道通信题。

Aitana 和 Bruno 在游玩 Bolivia 的一座国家公园。园内有 NN 个景点,(N−1)(N-1) 条道路,每条道路连接两个景点。可以通过道路从任意一个景点到达任意一个景点。

他们在游玩时走散了。此刻开始,他们必须同时抵达某个景点,在那里汇合。然而,身处亚马逊雨林深处,他俩无法互相通信。他们唯一可以依靠的是手头上的地图,地图刻画了公园的结构。他俩在自己的地图上给每个景点标号了 0,1,…,N−10,1,\ldots,N-1。然而,Aitana 和 Bruno 的标号可能不同。

为了汇合,Aitana 和 Bruno 现在开始移动。每一轮,他们同时做以下两件事之一:通过一条道路移动到相邻的景点,或者原地不动。

编程实现一个能够让 Aitana 和 Bruno 汇合的策略。本题中,如果在 6d6d 轮内让他俩汇合,可以获得满分;这里,dd 是 Aitana 景点到 Bruno 景点最短路上的边数。注意,如果他们在道路中间相遇,不算作汇合。

本题单个测试点内有 QQ 组测试数据。

形式化题意

我们形式化地描述题意。

国家公园的每个景点都分配了一个 0∼N−10\sim N-1 的标号,第 jj(0≤j≤N−20\le j\le N-2)条道路连接标号为 uj,vju_j,v_j 的景点。标号为 ii(0≤i≤N−10\le i\le N-1)的景点在 Aitana 的地图上标号为 pip_i,在 Bruno 的地图上标号 qiq_i。这里,(p0,p1,…,pN−1)(p_0,p_1,\ldots,p_{N-1}) 和 (q0,q1,…,qN−1)(q_0,q_1,\ldots,q_{N-1}) 是 (0,1,…,N−1)(0,1,\ldots,N-1) 的排列。

Aitana 知道,对于 j=0,1,…,N−2j=0,1,\ldots,N-2,有一条连接标号 Aj,BjA_j,B_j 的景点的道路,并且此时她位于标号为 SS 的景点。这里的「标号」指的是 Aitana 地图上的标号。从而,第 j (0≤j≤N−2)j\, (0\le j\le N-2) 条路连接着标号 puj,pvjp_{u_j},p_{v_j} 的景点,并且令 Aitana 现在所在的景点标号为 ss,有 S=psS=p_s。注意,道路不一定按顺序给出,也不一定是 uj,vju_j,v_j 的顺序。类似地,Bruno 知道,对于 j=0,1,…,N−2j=0,1,\ldots,N-2,有一条连接标号 Cj,DjC_j,D_j 的景点的道路,并且此时她位于标号为 TT 的景点。这里的「标号」指的是 Bruno 地图上的标号。特别地,令 Bruno 现在所在的景点标号为 tt,有 T=qtT=q_t。

根据已知信息,Aitana 和 Bruno 决定他们接下来 10N10N 轮的动向。换言之,Aitana 选定标号序列 x0,x1,…,x10Nx_0,x_1,\ldots,x_{10N},Bruno 选定标号序列 y0,y1,…,y10Ny_0,y_1,\ldots,y_{10N},表示他们各自的动向。以下条件必须满足:

  • x0=Sx_0=S,∀1≤k≤10N\forall 1\le k\le 10N,要么 xk=xk−1x_k=x_{k-1},要么(在 Aitana 的地图中)标号 xk,xk−1x_k,x_{k-1} 的节点有道路连接。
  • y0=Ty_0=T,∀1≤k≤10N\forall 1\le k\le 10N,要么 yk=yk−1y_k=y_{k-1},要么(在 Bruno 的地图中)标号 yk,yk−1y_k,y_{k-1} 的节点有道路连接。

Aitana 与 Bruno 汇合时的轮数 k∗k^* 指最小的满足(Aitana 的地图中)标号 xkx_k 的景点与(Bruno 的地图中)标号 yky_k 的景点代表着同一个景点的 kk。获得满分,当且仅当 k∗≤6dk^*\le 6d。

实现细节

这是一道通信题。你不应该,也不需要定义 main 函数。

不要 #include "telepathy.h"\texttt{\#include "telepathy.h"}。

你应该定义以下的函数:

vector<int> Aitana(int N, vector<int> A, vector<int> B, int S, int subtask);

该函数实现了 Aitana 的策略。每组测试数据中该函数被调用恰好一次,所以该函数一共会被调用 QQ 次。

  • N\texttt{N} 指国家公园的景点数 NN。
  • A,B\texttt{A},\texttt{B} 均为长度 N−2N-2 的数组,∀0≤j≤N−2\forall 0\le j\le N-2,A[j],B[j]\texttt{A[j]},\texttt{B[j]} 是一条道路连接着的两个景点的标号 Aj,BjA_j,B_j。
  • S\texttt{S} 为 Aitana 当前所在景点的标号。
  • subtask\texttt{subtask} 指该测试点所在的子任务编号,只能为 1,2,31,2,3 之一。
  • 返回一个数组 [x0,x1,…,x10N][x_0,x_1,\ldots,x_{10N}],描述 Aitana 的动向。
  • 返回的数组长度必须为 10N+110N+1,否则会被判为 Wrong Answer [1]\texttt{Wrong Answer\,[1]}。
  • 对于任意 k (0≤k≤10N)k\, (0\le k\le 10N),必须有 0≤xk≤N−10\le x_k\le N-1,否则会被判为 Wrong Answer [2]\texttt{Wrong Answer\,[2]}。
  • 必须有 x0=Sx_0=S,否则会被判为 Wrong Answer [3]\texttt{Wrong Answer\,[3]}。
  • 对于任意 k (1≤k≤10N)k\, (1\le k\le 10N),要么 xk=xk−1x_k=x_{k-1},要么标号 xk,xk−1x_k,x_{k-1} 的景点有道路连接。否则会被判为 Wrong Answer [4]\texttt{Wrong Answer\,[4]}。

以上的「标号」指的是 Aitana 地图上的标号。

vector<int> Bruno(int N, vector<int> C, vector<int> D, int T, int subtask);

该函数实现了 Bruno 的策略。每组测试数据中该函数在调用 Aitana 后被调用恰好一次,所以该函数一共会被调用 QQ 次。

  • N\texttt{N} 指国家公园的景点数 NN。
  • C,D\texttt{C},\texttt{D} 均为长度 N−2N-2 的数组,∀0≤j≤N−2\forall 0\le j\le N-2,C[j],D[j]\texttt{C[j]},\texttt{D[j]} 是一条道路连接着的两个景点的标号 Cj,DjC_j,D_j。
  • T\texttt{T} 为 Bruno 当前所在景点的标号。
  • subtask\texttt{subtask} 指该测试点所在的子任务编号,只能为 1,2,31,2,3 之一。
  • 返回一个数组 [y0,y1,…,y10N][y_0,y_1,\ldots,y_{10N}],描述 Bruno 的动向。
  • 返回的数组长度必须为 10N+110N+1,否则会被判为 Wrong Answer [5]\texttt{Wrong Answer\,[5]}。
  • 对于任意 k (0≤k≤10N)k\, (0\le k\le 10N),必须有 0≤yk≤N−10\le y_k\le N-1,否则会被判为 Wrong Answer [6]\texttt{Wrong Answer\,[6]}。
  • 必须有 y0=Ty_0=T,否则会被判为 Wrong Answer [7]\texttt{Wrong Answer\,[7]}。
  • 对于任意 k (1≤k≤10N)k\, (1\le k\le 10N),要么 yk=yk−1y_k=y_{k-1},要么标号 yk,yk−1y_k,y_{k-1} 的景点有道路连接。否则会被判为 Wrong Answer [8]\texttt{Wrong Answer\,[8]}。

以上的「标号」指的是 Bruno 地图上的标号。

如果在 10N10N 轮内 Aitana 和 Bruno 没有汇合,换句话说,∀0≤k≤10N\forall 0\le k\le 10N,(Aitana 的地图中)标号 xkx_k 的景点与(Bruno 的地图中)标号 yky_k 的景点均为不同的景点,你的程序会被判为 Wrong Answer [9]\texttt{Wrong Answer\,[9]}。

重要说明

  • 你可以在程序中定义其他函数或使用全局变量。在实际评测时,你的程序将会以两个不同的进程(Aitana,Bruno)运行,这两个进程无法共享全局变量。
  • 你的程序不得使用标准输出输出,禁止以任何方式与任何文件交互。你可以输出调试信息到标准错误流。

编译运行

你可以在「附件」中下载附件压缩包,压缩包中包含 Sample Grader 和本题的示例文件。

Sample Grader 是文件 grader.cpp\texttt{grader.cpp}。为测试程序,将 $\texttt{grader.cpp},\texttt{telepathy.cpp},\texttt{telepathy.h}$ 置于同一目录下,用以下命令来编译:

g++ -std=gnu++20 -O2 -o grader grader.cpp telepathy.cpp

此外,你也可以运行压缩包中的 compile.sh\texttt{compile.sh} 来编译:

./complie.sh

若编译成功,会生成名为 grader\texttt{grader} 的可执行文件。

注意,实际测评时使用的 Grader 与 Sample Grader 不同。Sample Grader 以单进程方式执行,从标准输入流读入数据并将结果输出至标准输出流。

输入格式

Sample Grader 从标准输入流读入以下格式的数据(这里,测试数据编号 0∼Q−10\sim Q-1,subtask\mathrm{subtask} 指子任务编号):

subtask\mathrm{subtask}
QQ
(第 00 组数据的内容)
(第 11 组数据的内容)
⋮\vdots
(第 (Q−1)(Q-1) 组数据的内容)

每组数据格式如下:

NN
u0u_0 v0v_0
u1u_1 v1v_1
⋮\vdots
un−2u_{n-2} vn−2v_{n-2}
p0p_0 p1p_1 …\ldots pN−1p_{N-1}
q0q_0 q1q_1 …\ldots qN−1q_{N-1}
ss tt

关于各变量的含义,请阅读「形式化题意」部分。注意没有直接输入 Aitana 地图和 Bruno 地图的信息。

将道路打乱的方式由伪随机数决定,伪随机数的结果在各次运行中均相同。如果想要更换随机数种子,将随机数种子作为第一个参数运行 Sample Grader:

./grader 20250615

输出格式

Sample Grader 输出 QQ 行到标准输出流,依次表示每组测试数据的信息:

  • 若该组数据正确,依次输出汇合轮数 k∗k^{*} 和 dd(Aitana 当前所在景点与 Bruno 当前所在景点的最短路上的边数),例如 Case #0: Accepted 5 2\texttt{Case \#0: Accepted 5 2}。
  • 否则,输出错误类型,如 Case #0: Wrong Answer [1]\texttt{Case \#0: Wrong Answer [1]}。
2
1
3
0 1
1 2
2 1 0
2 0 1
1 0

提示

注意事项

实际评测时,输入未必在程序执行前就确定了,有可能会根据 Aitana 和 Bruno 的返回值确定。

样例解释

返回值中,若干部分被省略了,实际上每个返回值都是长度为 3131 的数组。

调用 Aitana:Aitana(3,[0,1],[1,2],1,2)\texttt{Aitana(3,[0,1],[1,2],1,2)},返回 [1,0,0,1,2,...,2]\texttt{[1,0,0,1,2,...,2]}。

调用 Bruno:Bruno(3,[1,0],[2,0],2,2)\texttt{Bruno(3,[1,0],[2,0],2,2)},返回 [2,2,0,0,1,...,1]\texttt{[2,2,0,0,1,...,1]}。

该样例中,国家公园的结构以及 Aitana、Bruno 地图上的信息如图所示:

Aitana 的动向是:每一轮中,她分别在(她地图中)标号 1,0,0,1,2,…,21,0,0,1,2,\ldots,2 的景点。Bruno 的动向是:每一轮中,他分别在(他地图中)标号 2,2,0,0,1,…,12,2,0,0,1,\ldots,1 的景点。他们第 33 轮结束时汇合。此时,Aitana 在(她地图中)标号 11 的景点,Bruno 在(他地图中)标号 00 的景点,这两个实际上是同一个景点。

数据范围

本题中,单组数据中至多有 201201 个测试点(即 1≤Q≤2011\le Q\le 201)。每个测试点满足以下的限制:

  • 2≤N≤2002\le N\le 200;
  • (p0,p1,…,pN−1)(p_0,p_1,\ldots,p_{N-1}) 是 (0,1,…,N−1)(0,1,\ldots,N-1) 的排列;
  • (q0,q1,…,qN−1)(q_0,q_1,\ldots,q_{N-1}) 是 (0,1,…,N−1)(0,1,\ldots,N-1) 的排列;
  • 0≤uj≤N−1 (0≤j≤N−2)0\le u_j\le N-1\, (0\le j\le N-2);
  • 0≤vj≤N−1 (0≤j≤N−2)0\le v_j\le N-1\, (0\le j\le N-2);
  • 从任意景点,可通过道路移动到任意景点;
  • 0≤s≤N−10\le s\le N-1;
  • 0≤t≤N−10\le t\le N-1;
  • s≠ts\neq t。

子任务

  • Subtask 1 (40 pts)\text{Subtask 1 (40 pts)}:(p0,p1,…,pN−1)(p_0,p_1,\ldots,p_{N-1})=(q0,q1,…,qN−1)=(0,1,…,N−1)(q_0,q_1,\ldots,q_{N-1})=(0,1,\ldots,N-1);
  • Subtask 2 (40 pts)\text{Subtask 2 (40 pts)}:uj=j,vj=j+1u_j=j,v_j=j+1(0≤j≤N−20\le j\le N-2);
  • Subtask 3 (20 pts)\text{Subtask 3 (20 pts)}:无额外限制。

计分方式

令 k∗k^{*} 表示 Aitana 和 Bruno 汇合的轮数,dd 表示 Aitana 当前所在景点与 Bruno 当前所在景点的最短路上的边数。令 α\alpha 表示该子任务重 k∗d\frac{k^*}{d} 的最大值。

如果该子任务中你的程序被判为错误,得零分。否则,按照以下方式得分(若同时满足多个条件,则取最高的分数):

  • 若任意数据都有 k∗≤10Nk^*\le 10N,得 15%15\% 的分。
  • 若任意数据都有 k∗≤max⁡(10d,N)k^*\le \max(10d,N),得 25%25\% 的分。
  • 若任意数据都有 k∗≤10dk^*\le 10d:
    • 若 9<α≤109\lt \alpha\le 10,得 40%40\% 的分;
    • 若 0<α≤90\lt \alpha\le 9,得 ⌊100−20(α−6)⌋%\lfloor 100-20(\alpha-6)\rfloor \% 的分;
    • 若 α≤6\alpha\le 6,得 100%100\% 的分。