P11984 [JOIST 2025] 占卜 3 / Fortune Telling 3
题目背景
请使用 C++ 20 提交。不要引入 `anna.h` 和 `bruno.h`,并在代码头加入以下语句:
```cpp
int DrawCard(int);
```
题目描述
**这是一道通信题。交互库是非自适应的。**
Anna 和 Bruno 在玩一种用卡牌进行的占卜游戏 $Q$ 次,规则如下。
1. 有许多上面写着 $0$ 或 $1$ 的卡牌叠成一堆。Anna 从牌堆中一次抽出 $N$ ($=900$) 张卡牌。Anna 和 Bruno 知道 $N$ 的值。
2. 每次抽到卡牌时,她会决定是弃掉这张牌还是将其放到桌上。
- 如果她选择将牌放到桌上,她会把这张牌插入桌上的卡牌序列中。
- 形式化地,当桌上有 $l$ 张卡牌时,她选定非负整数 $x$($0 \leq x \leq l$),并将这张牌放在桌上从左数第 $x$ 张卡牌右侧。
- 当 $x = 0$ 时,她将这张牌放在桌上卡牌序列的最左侧。
3. 当 Anna 抽完并处理完 $N$ 张卡牌后,她的操作结束。**占卜结果**是这 $N$ 张卡牌中上面写着数字 $1$ 的卡牌数量。
4. 当 Anna 结束操作后,Bruno 会看到桌上的卡牌序列。基于这些信息,他需要猜出占卜结果。
如果 Bruno 猜对了,占卜就算成功。
当桌上的卡牌越少时,占卜被认为越高明。
请编写一个程序,实现 Anna 和 Bruno 的策略,使得全部 $Q$ 次占卜都成功。
在本题中,Anna 放在桌上的卡牌越少,得分越高。
### 实现细节
你不应该,也不需要实现 `main` 函数。
在洛谷上评测时,你只需要提交一个文件。
对于 Anna 的策略,你应该实现以下的函数:
```cpp
void Anna(int N);
```
该函数将被调用 $Q$ 次。第 $i$ 次调用表示第 $i$ 次占卜的过程。
参数 `N`($N=900$)代表卡牌的数量。
每次占卜,该函数必须调用以下的函数 $(N+1)$ 次:
```cpp
int DrawCard(int x);
```
使用此函数,Anna 从牌堆中抽卡,并选择丢弃或放置在桌面上。她通过第 $j$ 次调用($1 \leq j \leq N$)的返回值获取第 $j$ 张卡片上的数字。她通过第 $k$ 次调用($2 \leq k \leq N + 1$)的参数指定对第 $(k - 1)$ 张卡片的操作。
- 第 $j$ 次调用($1 \leq j \leq N$)的返回值为 $0$ 或 $1$,表示第 $j$ 张卡片上的数字。
- 特别地,第 $(N + 1)$ 次调用的返回值为 $-1$,表示 Anna 已完成抽卡。
- 第 $1$ 次调用的参数 $x$ 必须为 $-1$,否则程序将被判定为 $\texttt{Wrong Answer [1]}$。
- 第 $k$ 次调用的参数 $x$ 表示对第 $(k - 1)$ 张卡片的操作:
- 若 $x = -1$,则丢弃该卡片;
- 若 $0 \leq x$,则将卡片放置在桌面上当前最左数第 $x$ 张卡片的右侧;当 $x = 0$ 时,卡片置于桌面序列的最左侧。
- 参数需满足 $-1 \leq x \leq l$($l$ 为当前桌面卡片数),否则程序将被判定为 $\texttt{Wrong Answer [2]}$。
- 若调用 `DrawCard` 函数的次数不为 $(N + 1)$,程序将被判定为 $\texttt{Wrong Answer [3]}$。
---
对于 Bruno 的策略,你应该实现以下的函数:
```cpp
int Bruno(int N, int L, std::vector C)
```
该函数在每次调用 `Anna` 函数后被调用恰好一次,总计 $Q$ 次。
第 $i$ 次调用($1 \leq i \leq Q$)对应第 $i$ 次占卜流程,需返回 $N$ 张卡牌中上面写着数字 $1$ 的卡牌数量。
- 参数 $N$ 表示 Anna 抽取的卡片总数。
- 参数 $L$ 表示桌面上的卡片数量。
- 参数 $C$ 为长度为 $L$ 的数组,其中 $C[l-1]$ 表示桌面上第 $l$ 张最左侧卡片($1 \leq l \leq L$)的数字。
- 若返回值不等于 $N$ 张卡牌中上面写着数字 $1$ 的卡牌数量,程序将被判定为 $\texttt{Wrong Answer [4]}$。
### 注意事项
- 交互库是**非自适应的**。
- 程序可定义其他内部函数或全局变量,但需在匿名命名空间中声明以避免冲突。
- 由于洛谷评测系统的限制,Anna 和 Bruno 将在同一进程中运行。请注意清空。
- 禁止使用标准输入输出或通过其他方式与外部文件通信,但可将调试信息输出至标准错误流。
### 编译与测试
下载附件中的压缩包,将以下文件置于同一目录:
- $\boldsymbol{grader.cpp}$;
- $\boldsymbol{Anna.cpp}$;
- $\boldsymbol{Bruno.cpp}$;
- $\boldsymbol{Anna.h}$;
- $\boldsymbol{Bruno.h}$。
运行以下命令编译:
```bash
g++ -std=gnu++20 -O2 -o grader grader.cpp Anna.cpp Bruno.cpp
```
或直接运行压缩包中的 $\boldsymbol{compile.sh}$:
```bash
./compile.sh
```
输入格式
Sample Grader 输入格式如下:
> $Q$ $N$
> $A_{1,1}$ $A_{1,2}$ $\cdots$ $A_{1,N}$\
> $A_{2,1}$ $A_{2,2}$ $\cdots$ $A_{2,N}$\
> $\vdots$\
> $A_{Q,1}$ $A_{Q,2}$ $\cdots$ $A_{Q,N}$
输出格式
Sample Grader 会向标准输出和标准错误流输出以下信息:
- 若程序被判定为正确,Sample Grader 将以 $\texttt{Accepted: 100}$ 格式输出桌面上卡片数量的最大值。
- 若程序被判定为错误,Sample Grader 将以 $\texttt{Wrong Answer [1]}$ 格式输出错误类型。
若程序同时满足多个错误类型的条件,Sample Grader 仅报告其中一个。当检测到错误条件时,Sample Grader 可能终止执行。
说明/提示
### 样例交互
样例输入包含 $Q (= 2)$ 次占卜流程,Anna 从牌堆抽取的卡片数为 $N (= 5)$。
| 调用 | 返回值 | 调用 | 返回值 |
|:-:|:-:|:-:|:-:|
| $\texttt{Anna(5) }$ | $ $ | $\texttt{DrawCard(-1)}$ | $0 $ |
| $\texttt{ }$ | $ $ | $\texttt{DrawCard(0) }$ | $1 $ |
| $\texttt{ }$ | $ $ | $\texttt{DrawCard(-1)}$ | $0 $ |
| $\texttt{ }$ | $ $ | $\texttt{DrawCard(1) }$ | $0 $ |
| $\texttt{ }$ | $ $ | $\texttt{DrawCard(-1)}$ | $1 $ |
| $\texttt{ }$ | $ $ | $\texttt{DrawCard(1) }$ | $-1$ |
| $\texttt{Bruno(5, 3, [0, 1, 0]) }$ | $2$ | $\texttt{ }$ | $ $ |
| $\texttt{Anna(5) }$ | $ $ | $\texttt{DrawCard(-1)}$ | $1 $ |
| $\texttt{ }$ | $ $ | $\texttt{DrawCard(0) }$ | $1 $ |
| $\texttt{ }$ | $ $ | $\texttt{DrawCard(1) }$ | $0 $ |
| $\texttt{ }$ | $ $ | $\texttt{DrawCard(2) }$ | $1 $ |
| $\texttt{ }$ | $ $ | $\texttt{DrawCard(-1)}$ | $0 $ |
| $\texttt{ }$ | $ $ | $\texttt{DrawCard(1) }$ | $-1$ |
| $\texttt{Bruno(5, 4, [1, 0, 1, 0])}$ | $3$ | $\texttt{ }$ | $ $ |
第一次占卜流程的操作步骤如下:
1. Anna 抽取第 $1$ 张卡,数字为 $0$。
2. Anna 选择将卡片置于桌面最左侧,桌面序列变为 $0$。接着抽取第 $2$ 张卡,数字为 $1$。
3. Anna 选择丢弃此卡。随后抽取第 $3$ 张卡,数字为 $0$。
4. Anna 选择将此卡放置在桌面上第 $1$ 张最左侧卡片的右侧,桌面序列变为 $0, 0$。接着抽取第 $4$ 张卡,数字为 $0$。
5. Anna 选择丢弃此卡。随后抽取第 $5$ 张卡,数字为 $1$。
6. Anna 选择将此卡放置在桌面上第 $1$ 张最左侧卡片的右侧,桌面序列变为 $0, 1, 0$。
此时,Bruno 看到的桌面序列为 $0, 1, 0$,推断 Anna 抽取的卡片中数字为 $1$ 的数量为 $2$(正确)。桌面上卡片数为 $L = 3$。
**第二次占卜流程**中,桌面上卡片数为 $L = 4$。
注:此样例输入不满足题目约束。附件压缩包中,`sample-01-in.txt` 对应样例输入 1,`sample-02-in.txt` 为满足约束的样例输入。
### 数据范围
- $1\le Q\le 100$;
- $N=900$;
- $\forall 1\le i\le Q, 1\le j\le N$,$A_{i,j}\in \{0,1\}$。
### 计分方式
若程序在任何测试用例中被判定为 $\texttt{Wrong Answer [1] – [4]}$(见【实现细节】)、TLE、MLE 或 RE 等,则得 $0$ 分。
若程序在所有测试用例中均被判定为正确,则得分由所有测试用例中所有占卜流程内调用 `DrawCard` 函数时参数满足 $0 \leq x$ 的最大次数决定。
设该次数为 $L$,得分规则如下:
| 条件 | 得分 |
|:-:|:-:|
| $500 < L$ | $3$ |
| $14 < L \leq 500$ | $\displaystyle \left\lfloor100 \times \left( \frac{2.5}{L - 11.5} \right)^{0.35}\right\rfloor$ | 向下取整($\lfloor \cdot \rfloor$) |
| $L \leq 14$ | $100$ |