Farmer G 拥有一片被电围栏包围的大型牧场。围栏由围栏桩和连接相邻桩的直线段导线组成。围栏显然不会自交,即没有任何一段导线与另一段导线相交。
Farmer G 得知一条新的直线道路可能会穿过他的牧场。他来到现场,发现道路的两个端点已经被两个桩 $a$ 和 $b$ 标记。他意识到道路所在的直线将他牧场的内部区域分割成了若干个不相交的区域。
Farmer G 想要确定道路两侧分别形成了多少个区域。他发现没有任何围栏桩位于道路所在的直线上。此外,如果某段导线与道路所在的直线相交,那么交点位于端点 $a$ 和 $b$ 之间。
不幸的是,Farmer G 没有测量两个桩之间距离的仪器。他只能观察桩的方位,即他可以走到任何一个桩 $p$(注意道路端点也是桩),并看向桩 $q$,观察第三个桩 $r$ 是位于他的左侧、右侧,还是三点共线。幸运的是,Farmer G 随身携带了笔记本电脑(一如既往),因此他可以进行复杂的计算。
任务
你需要编写一个程序,计算由于道路将牧场分割而产生的位于道路左侧和右侧的不相交区域的数量。
交互
为了执行查询,你将获得一个包含三个操作的库 lookup:
GetN:在程序开始时调用一次,无需参数;它返回 $N$,即围栏桩的数量。在第一次调用Drift之前必须先调用GetN。Drift:调用时传入三个桩的标签作为参数。Drift(x, y, z)在从 $x$ 看向 $y$ 时,如果桩 $z$ 位于左侧,则返回 $1$;如果 $z$ 位于右侧,则返回 $-1$;如果三点共线,则返回 $0$。围栏桩的编号为 $1$ 到 $N$,道路端点 $a$ 和 $b$ 的编号分别为 $N+1$ 和 $N+2$。围栏的导线段连接编号为 $i$ 和 $(i \pmod N) + 1$ 的围栏桩。如果Drift的参数中至少有两个相等,它也返回 $0$。Answer:在最后调用一次;它报告结果并正确终止程序的执行。Answer有两个整数参数。第一个和第二个参数必须分别是位于道路左侧和右侧的不相交区域的数量。(如果围栏桩 $p$ 位于道路的左侧或右侧,Drift(a, b, p)分别返回 $1$ 或 $-1$。)
你的程序不允许读取或写入文件。输入和输出由库处理。
实现细节
Pascal 程序员说明:在源代码中包含导入语句 uses lookup;。
C/C++ 程序员说明:在源代码中使用指令 #include "lookup.h",在任务目录中创建一个项目文件,将文件 fence.c (fence.cpp)、lookup.h 和 lookup.o 添加到该项目中,然后编译和/或构建你的程序。(使用 Dev-C++ IDE 时,选择 Project/Project Options/Files 菜单,选择文件 lookup.o,取消勾选“include in compilation”并勾选“include in linking”)。
命令行编译:
gcc/g++ -O2 -static -o fence fence.c lookup.o -lm
实验
你获得了一个包含 WinXP 和 Linux 库的工具集。你可以从竞赛服务器下载 zip 压缩包。将相应的库文件复制到你的任务目录中。
该工具集包含一个测试生成器 testgener,用于生成包含有效随机样本输入的 fence.in 文件。testgener 需要一个整数输入参数 $N$,即围栏桩的近似数量。如果 $N < 300$,testgener 还会创建一个 PostScript 文件 fence.ps,用于可视化围栏的布局(你可以使用 gsview 或其他 PostScript 查看器查看)。生成的测试数据在 $N$ 为奇数和偶数时有很大不同;试着观察一下!
警告:testgener 无法生成所有可能的输入。
由 Answer 提交的解将被写入文件 fence.out。
你也可以通过创建文本文件 fence.in 来创建自己的输入。第一行必须包含四个整数,即道路端点的坐标。第二行必须包含 $N$,即围栏桩的数量。接下来的 $N$ 行,每行必须包含一对整数 $x, y$ ($-20\,000 \le x, y \le 20\,000$);第 $i+2$ 行的坐标对定义了编号为 $i$ 的围栏桩的坐标。
数据范围
- 围栏桩的数量 $N$ 满足 $3 \le N \le 100\,000$。
- FreePascal 库文件名:WinXP 下为
lookup.ppu和lookup.o,Linux 下为lookup.o。 - Pascal 函数声明:
function GetN: longint; function Drift(x, y, z: longint): integer; procedure Answer(x, y: longint); - C/C++ 库文件名:
lookup.h和lookup.o。 - C/C++ 函数声明:
long GetN(void); int Drift(long x, long y, long z); void Answer(long left, long right);
Figure 1. 道路将牧场分割成若干个不相交的区域