EagleBear2002 的博客

这里必须根绝一切犹豫,这里任何怯懦都无济于事

🫡Jo娜贝尔-题解

题面

请在南京大学校园网环境下访问:🫡Jo 娜贝尔 (Bye-JonaBell.c) (cpl.icu)

题解

50 分算法

课上讲过的作业题 JoJo 谜题 (josephus.c) (cpl.icu)

100 分算法

在模拟约瑟夫问题的过程中,增加一个数组 life[i],表示第 i 只 JonaBell 还有多少只尾巴。

life[i] == 0 时,意味着当前这只 JonaBell 已经出局,在数组中做标记,下次报数的时候跳过这只 JonaBell。

120 分算法

使用链表结构(后续课程会讲到)维护当前在游戏中的所有 JonaBell,这一优化可以大大提高算法效率,该算法可以处理 \(n=3000,k=3000\) 的数据规模。事实上这也是这道题目本来的第 10 个数据点的数据规模,后来出题人决定给大家一个拿满分的机会,缩小了数据规模的上限。

易错点

本题代码过于简单,没有易错点。

超越性的算法

如果有同学推算出根据 \(n,k,b,l\) 直接计算最终结果的通项公式,欢迎和出题助教联系。

标程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stdio.h>

const int N = 3005;

int main() {

int n, k, b, l;
scanf("%d%d%d%d", &n, &k, &b, &l);

int pre[N], next[N];
for (int i = 1; i <= n; ++i) {
pre[i] = i - 1;
next[i] = i + 1;
}
pre[1] = n;
next[n] = 1;

int life[N];
for (int i = 1; i <= n; ++i) {
life[i] = l;
}

int alive = n, cur = 1, cnt = 0, bullets = b;
while (alive > 1) {
if (++cnt == k) {
cnt = 0;
if (bullets > 0) {
bullets--;
if (--life[cur] == 0) {
alive--;
next[pre[cur]] = next[cur];
pre[next[cur]] = pre[cur];
}
} else {
bullets = b;
}
}

cur = next[cur];
}

for (int i = 1; i <= n; ++i) {
if (life[i] > 0) {
printf("%d\n", i);
}
}

return 0;
}