#P14643. [IATI2018 day2]Park

[IATI2018 day2]Park

Park(公园)

题目描述

Vasi 终于决定去鲁塞(Ruse)旅游,并在当地的公园里散步。她从导游那里得知,这座公园是一个长方形,它的两条长边长度都是 N。在这两条长边上,各有 N+1 个有趣的地点(咖啡馆、网球场、喷泉等等),因此一共有 2N+2 个地点。

这些地点按题图方式编号并通过小路连接。公园只有一个入口——编号为 1 的地点;也只有一个出口——编号为 2N+2 的地点。

所有小路都是单向的,散步时必须遵守它们的方向。小路方向满足以下条件:

  • 整张图中不存在有向环
  • 入口是唯一一个所有相邻小路都从这里出发的点;
  • 出口是唯一一个所有相邻小路都指向这里的点;
  • 对于其他所有点,既有入边也有出边。

如果一条小路的方向是从编号较小的地点指向编号较大的地点,我们称它的方向为正方向,记作 1;否则称为负方向,记作 0

Vasi 已经知道:

  • 从入口出发的两条小路一定是正方向;
  • 通向出口的两条小路也一定是正方向。

但是,其余小路的方向她并不知道。为了规划路线,她想要弄清楚所有小路的方向。

公园入口处有一台计算机,可以回答一种奇怪的询问:

给出若干条小路(用它们连接的两个地点编号表示),程序会返回这些小路方向值的**异或(XOR)**结果。

其中:

  • 正方向记为 1
  • 负方向记为 0
  • 如果只询问一条小路,那么返回值就是该小路本身的方向。

Vasi 希望在不询问太多次的前提下,确定所有小路的方向。

评测程序已经把这台计算机模拟出来了。你需要编写函数 run,通过调用给定接口进行询问,并最终汇报每一条小路的方向。


实现要求

这是一道提交函数题

你需要实现如下函数:

void run(int n);

该函数只会被调用一次,其中参数 n 就是题目中的 N

你提交的文件名应为:

park.cpp

并且文件开头必须包含:

#include "park.h"

你的代码中不能包含 main 函数。


交互接口

你可以调用评测器提供的如下两个函数:

bool get_xor(const std::vector<std::pair<int, int>>& edges);
void state_direction(const std::pair<int, int>& edge, bool direction);

get_xor

  • 返回参数 edges 中所有小路方向值的异或结果;
  • 每条小路用一对整数表示,即它连接的两个地点编号,二者顺序可以任意;
  • 该函数的时间复杂度和空间复杂度都与询问中的边数成线性关系。

state_direction

  • 用于向评测器声明某一条小路的真实方向;
  • 参数 edge 表示一条小路;
  • 参数 direction 表示你认定的方向:
    • 1:正方向(小编号指向大编号);
    • 0:负方向(大编号指向小编号)。

评测规则

如果出现以下任意情况,该测试点得分为 0

  • 你向 get_xorstate_direction 传入了不存在的小路
  • 你向 state_direction 声明了错误的方向
  • 程序结束时,仍有某些小路没有被声明方向

约束条件

  • 1 \le N \le 100000

评分标准

Q 为单个测试点中调用 get_xor 的次数。

你的程序只有在每个测试点都在时限内完成,且满足 Q \le 3N 时,才能得到非零分。

具体评分如下:

  • 15 分:所有测试均满足 Q \le 3N,但至少存在一个测试满足 Q > 2N
  • 45 分:所有测试均满足 Q \le 2N,但至少存在一个测试满足 Q > \left\lceil \frac{3N}{2} \right\rceil
  • 70 分:所有测试均满足 Q \le \left\lceil \frac{3N}{2} \right\rceil,但至少存在一个测试满足 Q > \left\lceil \frac{16N}{11} \right\rceil
  • 100 分:所有测试均满足 Q \le \left\lceil \frac{16N}{11} \right\rceil

本地测试

题目提供了文件 Lgrader.cpp,你可以把它与自己的程序一起编译运行。

运行后,它会先询问 N,然后依次询问所有小路的方向(输入 01),并打印出双方通信过程。

你可以根据需要自行修改该文件。

本地测评文件

头文件


关于系统测试与自适应数据

在某些你不知道的测试点上,评测器会采用自适应方式回答你的询问。也就是说,公园中小路的具体方向可能会随着你发出的询问不同而不同,只要始终满足题目给定条件即可。

普通提交时,你无法看到这种自适应机制的内部过程。

系统测试输入格式(供评测器内部使用)如下:

  • 一个正整数 N
  • 接下来是 4N+10/1,依次表示所有小路的方向。

这些小路按如下顺序给出:

(1,2), (1,3), (2,3), (2,4), ..., (k,k+1), (k,k+2), ...

样例通信

评测器调用

run(2)

通信过程

步骤 run 的操作 评测器的回答
1 run(2)
2 state_direction({1,2}, 1)
3 state_direction({1,3}, 1)
4 state_direction({4,6}, 1)
5 state_direction({5,6}, 1)
6 get_xor({{3,4},{3,5},{4,5}}) 1
7 get_xor({{3,5}})
8 state_direction({3,4}, 1)
9 state_direction({3,5}, 1)
10 state_direction({4,5}, 1)
11 get_xor({{2,3},{2,4}}) 0
12 state_direction({2,3}, 1)
13 state_direction({2,4}, 1)
14 函数结束

样例解释

  1. 评测器调用 run,其中 N=2

2-5. run 先声明了从入口出发的两条小路,以及通向出口的两条小路的方向。根据题意,这四条小路一定都是正方向,所以可以直接确定。

6-7. run 连续进行了两次异或询问,并且两次都得到了 1。这时分析三条边 (3,4)(3,5)(4,5) 的方向:

  • 由于第 7 步只询问了 {(3,5)},返回值是 1,所以 (3,5) 一定是正方向;
  • 再结合第 6 步对 {(3,4),(3,5),(4,5)} 的异或结果为 1,可以推出剩余两条边的方向只可能落在原题图示给出的两种方案中。

其中第二种方案会形成一个有向环,但题目明确保证图中不存在有向环,所以只能选择第一种方案。

因此 run 在第 8-10 步声明:

  • (3,4) 为正方向;
  • (3,5) 为正方向;
  • (4,5) 为正方向。
  1. 接着,run 询问 {(2,3),(2,4)} 的异或值,得到 0。这说明这两条边方向相同。

于是它们也只有原题图示中的两种可能方向方案。

12-13. 如果采用第一种方案,那么与点 2 相连的所有边都会指向点 2。但题目中只有一个点允许“所有相邻边都指向它”,那就是出口;而点 2 显然不是出口。

因此只能采用第二种方案,于是:

  • (2,3) 为正方向;
  • (2,4) 为正方向。
  1. 函数结束,总共使用了 3 次询问。

说明

本题为交互 / 提交函数题,因此没有传统意义上的样例输入与样例输出。上面的“样例通信”展示的是选手程序与评测器之间的一次交互过程。