#HK5015. 「POI2013 R3」第一名在哪里? Where is number one?

「POI2013 R3」第一名在哪里? Where is number one?

题目描述

题目译自 XX Olimpiada Informatyczna — III etap Gdzie jest jedynka?

Bajtazar 构思了一个从 11nn 的排列 PP,并希望你猜出数字 11 在排列中的位置。为了避免你盲目猜测,他会回答以下两种问题:

  • f(i,j,d)f(i, j, d):排列 PP 的第 ii 个元素与第 jj 个元素的差是否能被 dd 整除,即 dP[i]P[j]d \mid P[i] - P[j]
  • g(i,j)g(i, j):排列 PP 的第 ii 个元素是否大于第 jj 个元素?

其中,i,ji, j 为集合 {1,2,,n}\{1, 2, \ldots, n\} 中的任意索引,dd 为任意正整数。

在猜谜游戏中,你可无限制使用 ff 类型问题,但需尽量减少 gg 类型问题的数量。请编写一个程序,与 Bajtazar 提供的库交互,解决这个谜题。

交互方式

程序需在开头引入库:

  • C/C++: #include "cgdzlib.h"
  • Pascal: uses pgdzlib;

库提供以下函数:

  • inicjuj:返回 nn,需在程序开始时调用一次。
    • C/C++: int inicjuj();
    • Pascal: function inicjuj: LongInt;
  • f(i, j, d):向库询问 ff 类型问题,若 dP[i]P[j]d \mid P[i] - P[j] 返回 11,否则返回 00
    • C/C++: int f(int i, int j, int d);
    • Pascal: function f(i, j, d: LongInt): LongInt;
  • g(i, j):向库询问 gg 类型问题,若 P[i]>P[j]P[i] > P[j] 返回 11,否则返回 00
    • C/C++: int g(int i, int j);
    • Pascal: function g(i, j: LongInt): LongInt;
  • odpowiedz(k):告知库 11 位于排列的第 kk 位(即 P[k]=1P[k] = 1),调用后程序终止。
    • C/C++: void odpowiedz(int k);
    • Pascal: procedure odpowiedz(k: LongInt);

你的程序不得读取任何数据(包括标准输入或文件),不得向文件或标准输出写入内容。可向标准错误输出(stderr)写入诊断信息,但这会消耗时间。

编译与运行

在「文件」中,提供示例库以测试程序的格式正确性。库从标准输入读取排列描述,格式如下:

  • 第一行包含一个整数 nn,表示排列长度;
  • 第二行包含 nn 个空格分隔的整数,从 11nn,表示排列元素。

示例输入文件 gdz0.in 包含于该目录。程序运行结束后,库将输出到标准输出,说明你的回答是否正确及使用的 gg 类型问题数量。

同目录下提供示例代码 gdz.cgdz.cppgdz.pas,使用该库,但未最小化 gg 类型问题数量。

编译程序与库的命令如下:

  • C: gcc -O2 -static cgdzlib.c gdz.c -lm -o gdz
  • C++: g++ -O2 -static cgdzlib.c gdz.cpp -lm -o gdz
  • Pascal: ppc386 -O2 -XS -Xt gdz.pas

代码文件和库需位于同一目录。

样例

以下表格展示了一个与 Bajtazar 库交互的样例,成功找到 11 的位置:

问题编号 调用 结果 说明
- inicjuj 55 n=5n=5
11 f(1, 2, 2) 00 2P[1]P[2]2 \nmid P[1] - P[2]
22 g(1, 2) 00 P[1]<P[2]P[1] < P[2]
33 f(3, 2, 3) 11 3P[3]P[2]3 \mid P[3] - P[2]
44 g(2, 5) 11 P[2]>P[5]P[2] > P[5]
55 f(1, 3, 2) 11 2P[1]P[3]2 \mid P[1] - P[3]
66 f(1, 4, 3) 11 3P[1]P[4]3 \mid P[1] - P[4]
- odpowiedz(4) - 回答 k=4k=4

在第二个问题后,我们知道 P[2]1P[2] \neq 1。因此,第三个问题表明可能有:(P[2]=2,P[3]=5)(P[2]=2, P[3]=5)(P[2]=4,P[3]=1)(P[2]=4, P[3]=1)(P[2]=5,P[3]=2)(P[2]=5, P[3]=2)。第四个问题排除第一种可能。第五个问题表明 P[1]{3,4}P[1] \in \{3, 4\}。由于第六个问题确认 3P[1]P[4]3 \mid P[1] - P[4],故 P[1]=4P[1]=4P[4]=1P[4]=1。因此,11 位于位置 k=4k=4

此问题序列正确找到 11 的位置,但不会得分,因为对于 n=5n=5 的任意排列,M(5)=1M(5)=1,而示例使用了两个 gg 类型问题。ff 类型问题数量不影响评分。

数据范围与提示

M(n)M(n) 为在长度为 nn 的任意排列中找到 11 的位置所需的最少 gg 类型问题数量。你的程序仅当使用的 gg 类型问题数量不超过 M(n)M(n) 时,才能在该测试数据上得分。此外,程序需满足时间限制,因此 ff 类型问题的数量应合理(但无需最小化)。

对于 28%28\% 的测试数据,n5000n \leq 5000
所有测试数据满足 1n5000001 \leq n \leq 500000