QOJ.ac

QOJ

実行時間制限: 1 s メモリ制限: 512 MB 満点: 100

#3793. 杀手谜题

統計

你尝试过这个看起来很可怕的谜题吗?

  1. 答案为 b 的第一道题是哪一道? (a) 2; (b) 3; (c) 4; (d) 5; (e) 6;

  2. 答案与其下一题答案相同的唯一一道题是(例如选项 e 表示第 6 题和第 7 题的答案相同): (a) 2; (b) 3; (c) 4; (d) 5; (e) 6;

  3. 在 5 个选项中,哪一道题的答案与本题(即第 3 题)相同? (a) 1; (b) 2; (c) 4; (d) 7; (e) 6;

  4. 答案为 a 的题目有多少道? (a) 0; (b) 1; (c) 2; (d) 3; (e) 4

  5. 下列哪一道题的答案与本题相同? (a) 10; (b) 9; (c) 8; (d) 7; (e) 6;

  6. 答案为 a 的题目数量,等于答案为以下哪项的题目数量: (a) b; (b) c; (c) d; (d) e; (e) 以上皆非

  7. 本题答案与下一题答案的差值是多少(例如 a 和 b 的差值为 1)? (a) 4; (b) 3; (c) 2; (d) 1; (e) 0;

  8. 答案为元音字母的题目有多少道?(只有 a 和 e 是元音。其他为辅音) (a) 2; (b) 3; (c) 4; (d) 5; (e) 6

  9. 答案为辅音字母的题目数量是: (a) 一个质数;(b) 一个阶乘数;(c) 一个平方数;(d) 一个立方数;(e) 5 的倍数

  10. 本题的答案是: (a) a; (b) b; (c) c; (d) d; (e) e;

说明: 1. 确保你的答案没有自相矛盾。例如,第一题的答案不可能是 b。 2. 确保对于每一道题,只有你的答案是正确的,所有其他选项必须是不正确的。例如,如果你第 5 题的答案是 a,那么第 9、8、7、6 题的答案都不可能是 a! 3. 确保你的答案不会使任何题目无效。例如,如果第 2 题和第 3 题的答案相同,且第 8 题和第 9 题的答案也相同,那么第 2 题将无效(因为没有题目是“唯一满足条件的题目”)。

用手解出这个谜题是可能的,但作为一名程序员,用程序来解决它更有趣!

如何用程序解决谜题

一种方法是:枚举所有可能的答案($5^{10} = 9765625$),对于每一道题,检查是否只有你的答案是正确的。伪代码如下:

forall(answer_list):
 bad = False
 for testing_question in [1,2,3,4,5,6,7,8,9,10]:
 for testing_option in ["a","b","c","d","e"]:
 # your answer should be correct
 if testing_option == answer_list[testing_question] and 
check(testing_question, testing_option) == False:
 bad = True
 # other options must be incorrect
 if testing_option != answer_list[testing_question] and 
check(testing_question, testing_option) == True:
 bad = True
 if not bad:
 print answer_list

这里 "answer_list" 是一个字母列表(下标从 1 开始),其中第 i 个字母是第 i 题的答案。

信不信由你,唯一的答案是:cdebeedcba(如果你喜欢在每个答案前加上题号,它是 1c2d3e4b5e6e7d8c9b10a)。

很神奇吧?还有更多。你希望你的程序能解决其他一些谜题,但首先,你需要用一种形式化语言来描述这个谜题。

形式化谜题

本题使用一种 LISP 方言来表示谜题。别担心如果你不懂 LISP,它有非常简单的语法。(f a b) 表示调用函数 f,参数为 a 和 b。这就像 C/C++/Java 中的 f(a, b)。类似地,(f a (g b c) d) 就像 C/C++/Java 中的 f(a, g(b, c), d)。

以下是如何描述谜题中一道题的示例:

  1. (equal (answer 3) (answer (option-value))) a. 1 b. 2 c. 4 d. 7 e. 6

其中涉及两个非常重要的内置函数:

(answer idx) 返回上述伪代码中的 answer_list[idx]。 (option-value) 返回 testing_option 的文本的“求值结果”,将其视为一个表达式。

在上面的例子中,如果 testing_option 是 "c",那么 (option-value) 返回 4(一个整数),因为 4 是该题选项 "c" 中给出的表达式。注意,testing_option 的文本可以是一个复杂的表达式,而不仅仅是一个简单的值。请参考样例输入。

上述函数 check(testing_question, testing_option) 可以实现如下:

check(testing_question, testing_option): 1. 设置函数 (option-value),使其返回 testing_question 的 testing_option 的求值结果 2. 对 testing_question 的 LISP 表达式进行求值(例如上面例子中的 (equal (answer 3) (answer (option-value)))) 3. 如果在求值过程中抛出了未处理的异常,则返回 False 4. 如果第 2 步的结果是布尔值,则返回它;否则返回 False

有一个特殊的选项表达式:"none-of-above"。"none-of-above" 的结果取决于其他选项的求值结果。在本题中,每道题最多只能有一个 "none-of-above",且它必须是最后一个选项。

实现细节

以下是本题所用 LISP 方言的详细信息:

  • 有四种数据类型:整数、字符串、布尔值和函数。
  • 只有两个布尔值:true 和 false。注意没有“布尔字面量”,所以你不需要关心是使用 #t 和 #f(像 Scheme 中那样),还是 t 和 nil(像 Common Lisp 中那样)来表示布尔常量。
  • 整数始终是非负整数。
  • 字符串字面量始终用双引号括起来,例如 "a string"。
  • 没有变量。所有所谓的“标识符”(由字母和连字符组成)都是预定义的函数。

以下是预定义函数列表。以 ! 开头的函数意味着它可能会抛出异常,以 @ 开头的函数意味着它可以处理异常。像 C++/Java/Python 一样,一旦抛出异常,求值过程就会停止,除非有函数处理该异常。在下文中,iff 表示“当且仅当”。

基本函数

函数 说明
(equal a b) 当且仅当 a 和 b 类型相同且相等时返回 true。在本题中,你永远不需要比较两个函数。
(option-value) 如上所述。
!(answer idx) 如上所述。如果 idx 不是整数或不在 1~n 范围内(n 为题目总数),则抛出异常。
!(answer-value idx) 返回第 idx 题的选项 answer_list[idx] 的“求值结果”。出错时也会抛出异常。

谓词

谓词是一种特殊的函数。它总是接受任何类型的值并返回一个布尔值。

函数 说明
prime-p 当且仅当参数为正质数时返回 true
factorial-p 不言自明
square-p 不言自明
cubic-p 不言自明
vowel-p 当且仅当参数为单个字母且为元音时返回 true
consonant-p 不言自明

查询与统计

函数 说明
!@(first-question pred) 返回满足 pred 的第一道题的 id。如果未找到,则抛出异常。
!@(last-question pred) 返回满足 pred 的最后一道题的 id。如果未找到,则抛出异常。
!@(only-question pred) 返回满足 pred 的唯一一道题的 id。如果未找到或找到多于一道题,则抛出异常。
@(count-question pred) 返回满足 pred 的题目数量。
!(diff-answer idx1 idx2) 第 idx1 题和第 idx2 题答案的差值。出错时抛出异常,否则返回值始终为 0~m-1,其中 m 是每道题的选项数量。

注意,在前四个函数(带有 ‘@’ 标志的函数)中,如果在求值谓词时抛出了异常,该异常会被处理,且该谓词被视为不满足。例如,如果 answer_list 是 "abc",(count-question (make-answer-diff-next-equal 0)) 返回 0 且不会抛出异常,即使对第 3 题求值谓词(即 ((make-answer-diff-next-equal 0) 3))时抛出了异常。 然而,所有其他函数都不会处理异常。例如,如果只有 3 道题,(factorial-p (answer-value 5)) 将抛出异常而不是返回 false。

谓词生成器

还有一些函数可以即时创建谓词:

函数 说明
!(make-answer-diff-next-equal num) 返回一个谓词 (p idx),它对 (diff-answer idx idx+1) 求值,如果结果等于 num 则返回 true。如果 num 不是整数,则抛出异常。
(make-answer-equal a) 返回一个谓词 (p idx),它对 (answer idx) 求值,如果结果等于 a 则返回 true。
(make-answer-is pred) 返回一个谓词 (p idx),它对 (answer idx) 求值,如果结果满足 pred 则返回 true。
(make-answer-value-equal a) 不言自明。谓词对 (answer-value idx) 求值。
(make-answer-value-is pred) 不言自明。谓词对 (answer-value idx) 求值。
!(make-is-multiple num) 返回一个谓词 (p i),当且仅当 i 是整数且是 num 的倍数时返回 true。如果 num 不是整数,则抛出异常。
!(make-equal val) 返回一个谓词 (p v),当且仅当 (equal v val) 为 true 时返回 true。如果 val 既不是整数也不是字符串,则抛出异常。
(make-not pred) 返回一个谓词 (p v),当且仅当 (pred v) 为 false 时返回 true。
(make-and pred1 pred2) 返回一个谓词 (p v),当且仅当 (pred1 v) 和 (pred2 v) 均为 true 时返回 true。pred1 和 pred2 都需要被求值。不应进行短路操作。
(make-or pred1 pred2) 返回一个谓词 (p v),当且仅当 (pred1 v) 或 (pred2 v) 至少有一个为 true 时返回 true。pred1 和 pred2 都需要被求值。不应进行短路操作。

例如,(make-is-multiple 3) 返回一个“是 3 的倍数”的谓词,因此 ((make-is-multiple 3) 6) 返回 true,而 ((make-is-multiple 3) 10) 返回 false。类似地,(make-not (make-or square-p prime-p)) 返回一个“既不是平方数也不是质数”的谓词。

输入格式

最多有 50 个测试用例。每个测试用例以两个整数 n 和 m ($2 \le n \le 6, 2 \le m \le 5$) 开头,分别表示题目数量和每道题的选项数量。每道题用 m+1 行描述:题目的表达式和各个选项。题目编号为 1~n,选项标记为 a~e。选项是有效的表达式,且不会调用 option-value(调用 option-value 会使其递归!)。每道题后跟一个空行。大多数测试用例都很简单。

输出格式

对于每个测试用例,在第一行打印用例编号,然后按行打印答案列表,按升序排列。始终至少有一个答案。

样例

输入 1

3 3
(equal (option-value) (count-question (make-answer-equal "a")))
3
0
1
(equal (option-value) "a")
"c"
"b"
"a"
((option-value) (count-question (make-answer-equal "c")))
(make-and (make-is-multiple 2) (make-or factorial-p prime-p))
(make-not prime-p)
"none-of-above"
3 2
(equal (option-value) (answer 2))
"a"
"none-of-above"
(equal (option-value) (first-question (make-answer-diff-next-equal 0)))
1
2
((option-value) (last-question (make-answer-equal "b")))
(make-is-multiple 2)
(make-not (make-is-multiple 2))
3 2
(equal (option-value) (answer 1))
"a"
"b"
((option-value) (last-question (make-answer-diff-next-equal 0)))
(make-equal 2)
"none-of-above"
((option-value) (only-question (make-answer-equal "b")))
(make-is-multiple 2)
"none-of-above"
2 5
((option-value) (diff-answer 1 2))
factorial-p
prime-p
(make-not square-p)
(make-not cubic-p)
"none-of-above"
(equal (only-question (option-value)) 1)
(make-answer-is consonant-p)
(make-answer-is vowel-p)
(make-answer-value-equal 1)
(make-answer-value-is square-p)
"none-of-above"
2 2
(option-value)
(equal (first-question (make-answer-diff-next-equal 2)) (first-question (make-answer-diff-next-equal 2)))
"none-of-above"
(equal (option-value) 1)
1
2

输出 1

Case 1:
bcb
cca
Case 2:
aab
Case 3:
aba
Case 4:
ab
ee
Case 5:
ba

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.