Chika 有一副包含 $q$ 张扑克牌的牌组,每张牌上都写着不同的正整数。她想用这些牌和学生会的朋友们玩一些游戏,但她也想赢,所以她决定偷偷在牌的背面做标记。
这些牌都是 $2 \times 2$ 的正方形,左下角坐标为 $(0, 0)$,右上角坐标为 $(2, 2)$。Chika 在每张牌的背面画上特定的图案,以便日后通过观察图案就能知道牌正面写的是什么数字。她通过以下过程绘制图案:她可以随心所欲地(也可以 0 次)选择两个具有整数坐标且相对于牌左下角的不同点 $A$ 和 $B$,并在它们之间画一条直线段。
Chika 只会绘制有效的线段,即连接两个点 $A$ 和 $B$ 的线段,且该线段上不存在其他具有整数坐标的点($A$ 和 $B$ 除外)。例如,连接 $(0, 0)$ 和 $(2, 2)$ 的线段是无效的,因为它包含了点 $(1, 1)$;但连接 $(0, 0)$ 和 $(1, 1)$ 以及连接 $(1, 1)$ 和 $(2, 2)$ 的线段都是有效的,Chika 甚至可以在同一个图案中同时画出这两条线段。此外,请注意线段是没有方向的:从 $A$ 到 $B$ 的线段与从 $B$ 到 $A$ 的线段是完全相同的。
重要的是,Chika 希望确保无论牌如何旋转,她都能识别出她的牌。牌相对于原始方向可以逆时针旋转 0、90、180 或 270 度。
你的任务是帮助 Chika 为她牌组中的 $q$ 张牌设计图案,并在之后识别出这些牌。
实现细节
这是一个包含两个阶段的交互式任务,每个阶段涉及程序的独立运行。你需要实现两个函数:
BuildPattern函数,返回给定牌背面应绘制的图案。该函数在第一阶段会被调用 $q$ 次。GetCardNumber函数,返回带有给定图案(可能已旋转)的牌的数字。该函数在第二阶段会被调用 $q$ 次。
第一个函数:
std::vector<std::pair<std::pair<int, int>, std::pair<int, int>>> BuildPattern(int n);
该函数接收一个参数 $n$,即牌正面写的数字。你需要返回一个 std::vector,其中包含 Chika 为了日后识别而绘制的线段。线段由一对点表示,点由一对整数坐标 $(x, y)$ 表示,坐标相对于牌的左下角,其中 $0 \le x, y \le 2$。Chika 绘制的所有线段必须是有效的且两两不相同。保证所有 $q$ 次对 BuildPattern 的调用中,参数 $n$ 均不相同。
在接收到 $q$ 张牌的所有图案后,评测程序可能会对每个图案执行以下任意操作任意次数:
- 将整个图案逆时针旋转 0、90、180 或 270 度。
- 修改图案
std::vector表示中线段的顺序。 - 改变线段端点的顺序。(从 $A$ 到 $B$ 的线段可能变为从 $B$ 到 $A$ 的相同线段。)
第二个函数:
int GetCardNumber(std::vector<std::pair<std::pair<int, int>, std::pair<int, int>>> p);
该函数接收一个参数 $p$,即一个描述 Chika 在牌背面绘制的图案的 std::vector(基于之前对 BuildPattern 函数的返回值)。该函数必须返回牌正面写的数字 $n$。请记住,图案 $p$ 不一定是 BuildPattern 返回的原始形式;它可能经过了上述三种操作。牌的顺序也可能与第一阶段给出的顺序不同,但保证每张牌都会被使用且仅被使用一次。
数据范围
- $1 \le q \le 10\,000$。
- 对于所有对
BuildPattern函数的调用,$1 \le n \le 67\,000\,000$。 - 注意,存在能够构造图案以识别 $67\,000\,000$ 张不同牌的算法。
子任务
- 子任务 1(2 分):$n \le 2$。
- 子任务 2(9 分):$n \le 25$。
- 子任务 3(15 分):$n \le 1\,000$,且评测程序在第一阶段和第二阶段之间不会旋转图案。(评测程序可能会执行其他两种操作。)
- 子任务 4(3 分):$n \le 16\,000\,000$,且评测程序在第一阶段和第二阶段之间不会旋转图案。(评测程序可能会执行其他两种操作。)
- 子任务 5(24 分):$n \le 16\,000\,000$。
- 子任务 6(18 分):$n \le 40\,000\,000$。
- 子任务 7(29 分):无额外限制。
样例
样例 1
| 函数调用 | 返回值 | 说明 |
|---|---|---|
| 第一阶段开始 | - | - |
BuildPattern(3) |
{{{0, 0}, {2, 1}}, {{1, 1}, {2, 0}}} |
我们需要为 $2 \times 2$ 尺寸牌上的数字 3 创建图案。我们决定画 2 条线段: - 连接 $(0, 0)$ 和 $(2, 1)$, - 连接 $(1, 1)$ 和 $(2, 0)$。 |
BuildPattern(1) |
{{{0, 1}, {0, 0}}} |
我们需要为 $2 \times 2$ 尺寸牌上的数字 1 创建图案。我们决定画 1 条线段: - 连接 $(0, 1)$ 和 $(0, 0)$。 |
| 第一阶段结束 | - | - |
| 第二阶段开始 | - | - |
GetCardNumber({{{0, 0}, {0, 1}}}) |
1 | 我们得到一个由 1 条线段组成的图案: - 连接 $(0, 0)$ 和 $(0, 1)$。 这与我们通过绘制线段得到的图案相同: - 连接 $(0, 1)$ 和 $(0, 0)$。 这正是我们在第二次调用 BuildPattern 函数时返回的、具有相同方向(旋转 0 度)的图案。因此,我们返回 1。 |
GetCardNumber({{{1, 1}, {2, 2}}, {{1, 2}, {2, 0}}}) |
3 | 我们得到一个由 2 条线段组成的图案: - 连接 $(1, 1)$ 和 $(2, 2)$, - 连接 $(1, 2)$ 和 $(2, 0)$。 这是我们在第一次调用 BuildPattern 函数时返回的图案,逆时针旋转了 90 度。因此,我们返回 3。 |
| 第二阶段结束 | - | - |
接下来的三张图片依次表示:
- 第一次调用
BuildPattern返回的图案:
- 第二次调用
GetCardNumber接收到的参数图案,即第一个图案逆时针旋转 90 度后的结果:
- 第二次调用
BuildPattern返回的图案,这也是第一次调用GetCardNumber接收到的参数图案: