QOJ.ac

QOJ

حد الوقت: 20 s حد الذاكرة: 1024 MB مجموع النقاط: 45

#5938. 恰当的洗牌

الإحصائيات

题目描述

大小为 $N$ 的排列是一个包含 $N$ 个数字的序列,每个数字都在 $0$ 到 $N-1$ 之间,且每个数字恰好出现一次。它们可以以任何顺序出现。

大小为 $N$ 的排列有很多种(准确地说是 $N$ 的阶乘种,但这在本项目中并不重要)。有时我们只想随机选择一个,当然我们希望均匀地随机选择:大小为 $N$ 的每个排列被选中的概率应该相同。

以下是实现该目标的一种可能算法(我们在下文中称其为“好”算法)的伪代码:

for k in 0 .. N-1:
    a[k] = k
for k in 0 .. N-1:
    p = randint(k .. N-1)
    swap(a[k], a[p])

在上述代码中,randint(a .. b) 返回一个 $a$ 到 $b$ 之间(包含 $a$ 和 $b$)的均匀随机整数。

用文字描述该算法:我们从恒等排列开始:所有从 $0$ 到 $N-1$ 的数字按递增顺序排列。然后,对于 $0$ 到 $N-1$ 之间的每个 $k$,我们选取一个独立的均匀随机整数 $p_k$(范围在 $k$ 到 $N-1$ 之间),并将排列中位置 $k$(从 $0$ 开始计数)的元素与位置 $p_k$ 的元素进行交换。

以 $N=4$ 为例。我们从恒等排列开始:

0 1 2 3

现在 $k=0$,我们选取一个 $0$ 到 $3$ 之间的随机数 $p_0$。假设我们选到了 $2$。我们交换第 $0$ 个和第 $2$ 个元素,排列变为:

2 1 0 3

现在 $k=1$,我们选取一个 $1$ 到 $3$ 之间的随机数 $p_1$。假设我们又选到了 $2$。我们交换第 $1$ 个和第 $2$ 个元素,排列变为:

2 0 1 3

现在 $k=2$,我们选取一个 $2$ 到 $3$ 之间的随机数 $p_2$。假设我们选到了 $3$。我们交换第 $2$ 个和第 $3$ 个元素,排列变为:

2 0 3 1

现在 $k=3$,我们选取一个 $3$ 到 $3$ 之间的随机数 $p_3$。唯一的选择是 $3$。我们交换第 $3$ 个和第 $3$ 个元素,这意味着排列没有变化:

2 0 3 1

过程到此结束,这就是我们得到的随机排列。

还有许多其他算法可以均匀地生成随机排列。然而,也有许多看起来与此算法非常相似但并不均匀的算法——某些排列通过这些算法生成的概率比其他排列更高。

以下是此类算法中的一种“坏”算法。 采用上述“好”算法,但在每一步中,不是在 $k$ 到 $N-1$ 之间随机选取 $p_k$,而是在 $0$ 到 $N-1$ 之间随机选取。 这只是一个微小的改动,但现在某些排列出现的概率比其他排列更高了!

以下是该算法的伪代码(我们在下文中称其为“坏”算法):

for k in 0 .. N-1:
    a[k] = k
for k in 0 .. N-1:
    p = randint(0 .. N-1)
    swap(a[k], a[p])

在每个测试用例中,你将得到一个按以下方式生成的排列:首先,我们以 $50\%$ 的概率选择上述“好”算法或“坏”算法之一。然后,我们使用所选算法生成一个排列。你能仅通过观察排列来猜出选择了哪种算法吗?

解题说明

对于 Code Jam 来说,这个问题有点不同寻常。你将获得 $T = 120$ 个大小为 $N = 1000$ 的排列,并应为每个排列打印一个答案。然而,你不需要全部答对!如果你的答案中至少有 $G = 109$ 个用例是正确的,你的解法将被视为正确。但是,即使在你的答案不正确的用例中,你也必须遵循输出格式。唯一可以出错但仍被判定为正确的情况是:将 GOOD 误判为 BAD 或反之;但你仍然必须为每个用例打印 GOOD 或 BAD。

题目保证给出的排列是按照上述方法生成的,并且它们是相互独立生成的。

这个问题涉及随机性,因此即使是最好的解法也可能无法在某个输入中做出 $109$ 次正确的猜测,因为“好”算法和“坏”算法都可以生成任何排列。正因为如此,这个问题没有 Large 输入,只有 Small 输入,如果你认为自己运气不好,可以重试。请注意,如果之后你解决了该输入,会有通常的 $4$ 分钟罚时,即使你出错的唯一原因是运气。

根据我们对这个问题的经验,这种情况确实发生过(仅仅因为运气而得到错误答案);因此,如果你确信你的解法应该是有效的,但它失败了,那么再次尝试相同的解法可能是一个合理的策略。

祝你好运!

输入格式

输入的第一行给出了测试用例的数量 $T$(始终为 $120$)。每个测试用例包含两行:第一行包含单个整数 $N$(始终为 $1000$),下一行包含 $N$ 个空格分隔的整数——使用两种算法之一生成的排列。

输出格式

对于每个测试用例,输出一行,包含 "Case #$x$: $y$",其中 $x$ 是测试用例编号(从 $1$ 开始),$y$ 是 "GOOD" 或 "BAD"(不带引号)。如果你猜测该排列是由题目描述的第一种算法生成的,则输出 "GOOD";如果你猜测该排列是由题目描述的第二种算法生成的,则输出 "BAD"。

数据范围

$T = 120$ $G = 109$ $N = 1000$ 排列中的每个数字都在 $0$ 到 $N-1$ 之间(包含),且 $0$ 到 $N-1$ 中的每个数字在排列中恰好出现一次。

样例

样例输入 1

2
3
0 1 2
3
2 0 1

样例输出 1

Case #1: BAD
Case #2: GOOD

说明

样例输入不符合题目描述中的限制——真实的输入会大得多。

Discussions

About Discussions

The discussion section is only for posting: General Discussions (problem-solving strategies, alternative approaches), and Off-topic conversations.

This is NOT for reporting issues! If you want to report bugs or errors, please use the Issues section below.

Open Discussions 0
No discussions in this category.

Issues

About Issues

If you find any issues with the problem (statement, scoring, time/memory limits, test cases, etc.), you may submit an issue here. A problem moderator will review your issue.

Guidelines:

  1. This is not a place to publish discussions, editorials, or requests to debug your code. Issues are only visible to you and problem moderators.
  2. Do not submit duplicated issues.
  3. Issues must be filed in English or Chinese only.
Active Issues 0
No issues in this category.
Closed/Resolved Issues 0
No issues in this category.