loj#P3005. 「JOISC 2015 Day 4」Limited Memory

「JOISC 2015 Day 4」Limited Memory

题目描述

译自 JOISC 2015 Day4 T2「Limited Memory」。

注意:在 LibreOJ 上,由于语言限制,目前只支持以下语言的提交:

  • C
  • C++
  • C++ (NOI)
  • C++ 11
  • C++ 11 (Clang)
  • C++ 11 (NOI)
  • C++ 17
  • C++ 17 (Clang)

JOI 酱被选为了日本代表去参加国际信息学奥林匹克竞赛。为了提高信息处理速度,日本国际信息学奥林匹克竞赛委员会的 K 理事长提出了一个课题。

K 理事长在纸上写下了一个字符串 S S ,仅由 <>[] 组成,但是 JOI 酱不知道字符串具体是什么。JOI 酱会被告知字符串的长度,他的课题是判断字符串 S S 是不是一个合法字符串。合法字符串的定义如下:

  • 空字符串(长度为 0 0 的字符串)是合法字符串。
  • 假设 x x 是一个合法字符串,那么 <xx> 也是合法字符串。
  • 假设 x x 是一个合法字符串,那么 [xx] 也是合法字符串。
  • 假设 x x y y 都是合法字符串,那么 xyxy 也是合法字符串。

例如 <>[][<>]<> 都是合法字符串,而 ><[<]> 都不是合法字符串。

每天的中午,JOI 酱可以给 K 理事长打一个电话。电话里,JOI 酱可以指定一个整数 I I ,K 理事长会告诉他字符串 S S 的第 I I 个字符。

现在 JOI 酱有一个限制:不能用其它东西记录这个课题相关的笔记。JOI 酱每天晚上 2222 点睡觉,早上 66 点起床。在睡眠中,她只能在脑中记下 22 22 比特的信息。更准确的说,她会在睡前把一个 002221 2^{22}-1 的整数记在脑内,然后第二天醒来根据这个整数来做决策。由于字符串长度是一开始就被告知的,JOI 酱是一直知道这个信息的。

JOI 酱每天睡前可以记住一个整数,或者发邮件告诉 K 理事长字符串 S S 是不是一个合法字符串。在后者的情况下,这个课题就结束了,K 理事长会判定你是否完成了这个课题。注意,邮件必须在课题开始后 15000 15000 天内发给 K 理事长,不然你就算没有完成这个课题。

任务

请编写一个程序实现 JOI 酱的策略,并正确解出上述课题。

实现细节

你需要实现一个过程来确定字符串是否正确。请包含头文件 memory.h

程序需要实现以下过程。

  • int Memory(int N, int M)
    • 参数 N N 表示字符串 S S 的长度。
    • 参数 M M 表示上一天睡前记下的整数,在课题一开始的时候 M=0 M = 0
    • 在这个函数里必须恰好调用一次 Get 函数。
    • 函数的返回值必须是一个 0 0 2221 2^{22} - 1 的整数,或者 1 -1 ,或者 2 -2 。如果返回值不在这些数里面,那么你的程序会被判为 Wrong Answer [1]
      • 返回值是 0 0 2221 2^{22} - 1 的整数的话,表示这是睡前记下的数字。
      • 返回值是 1 -1 的话,表示用邮件回答 S S 是一个合法字符串。
      • 返回值是 2 -2 的话,表示用邮件回答 S S 不是一个合法字符串。
    • 这个函数应该理论上只依赖 N N M M Get 的返回值进行决策。在实际评测过程中这个函数会被调用 222×4 2^{22} \times 4 次,更详细的信息请参考「评分的顺序」。

此外,程序中可以调用如下函数。

  • char Get(int I)
    • 这个函数只能在调用 Memory 函数的时候被调用一次,如果调用了不止一次,你的程序会被判为 Wrong Answer [2]
    • 参数 I I 是一个 1 1 N N 的整数,不满足此条件时,会被判为 Wrong Answer [3]
    • 返回值是 S S 的第 I I 个字符。

评分的顺序

每个测试文件会包含多组测试数据,每组测试数据对应的字符串 S S 的长度 N N 是一样的。评测过程如下,如果一旦被判定为了 Wrong Answer,你的程序会立刻被终止。

  • 在给出参数 N N M M Get 的返回值的情况下,检查函数 Memory 的行为。也就是说对于满足 0M2221 0 \le M \le 2^{22} - 1 的整数 M M ,做如下操作:

    • 对于每个在 <>[] 的字符 cc,会执行如下操作:把 N N M M 作为参数传给 Memory 函数,当 Get 被调用的时候,把 cc 返回出去。用 m(M,c) m(M, c) 表示函数 Memory 的返回值。
    • 上述操作会调用 4 4 Memory 函数,需要检测 Get 的调用是否一致。如果 Get 被调用了,那么这 4 4 次传给 Get 的参数 I 必须一样。如果 Get 没有被调用,那么这 4 4 Memory 的返回值必须要一样。不满足此条件时,会被判为 Wrong Answer [4]。当 Get 被调用的时候,我们令 i(M) i(M) 表示 I I 的值(如果没有被调用 i(M)=1i(M)=1)。
  • 对于每组数组里的字符串 S S ,如下操作会被用来模拟课题描述

    • 一开始 M=0 M = 0
    • 重复执行如下操作:
      • c c S S 的第 i(M) i(M) 个字符。
      • M M 换为 m(M,c) m(M, c)
      • M=1 M = -1 或者 M=2 M = -2 的情况下,跳出这个循环,进入下个流程。
      • 如果循环了超过 15000 15000 次,你的程序会被判为 Wrong Answer [5]
    • 如果是以下某个情况,你的程序会被判为 Wrong Answer [6]
      • S S 是一个合法字符串,但是 M=2 M = -2
      • S S 不是一个合法字符串,但是 M=1 M = -1
  • 你的程序被认为是正确的。

编译与运行方法

「附加文件」中提供了 memory.hgrader-simple.cgrader-simple.cppgrader-strict.cgrader-strict.cpp 五个文件。若你编写的程序名称为 memory.cmemory.cpp,请运行以下命令来编译:

  • C 语言:
    • gcc -std=c11 -O2 -o grader-simple grader-simple.c memory.c -lm
    • gcc -std=c11 -O2 -o grader-strict grader-strict.c memory.c -lm
  • C++ 语言:
    • g++ -std=c++14 -O2 -o grader-simple grader-simple.cpp memory.cpp
    • g++ -std=c++14 -O2 -o grader-strict grader-strict.cpp memory.cpp

当命令成功时,会产生一个可执行文件 grader-simple 或者 grader-strict

注意实际评测时的程序与下发的样例评测程序并不相同。实际的 memory.h 函数实现将通过标准输入/输出与单独运行的交互器进行交互。

样例程序评测概要

grader-simple 不会模拟「评分的顺序」的第一步,但是会模拟课题的操作,具体可以参考「样例交互」。grader-strict 会严格按照「评分的顺序」执行。两者在输出上会有如下的不同:

  • grader-simple 不会输出 Wrong Answer [4],因为它并没有模拟这个操作
  • grader-simplegrader-strict 不会输出 Wrong Answer [6],但是会输出 MM 的值。

样例评测程序输入格式

grader-simplegrader-strict 将从标准输入读入以下数据。

  • 第一行包含两个整数 N N Q Q (0Q23110 \le Q \le 2^{31} - 1),表示字符串 S S 的长度和测试数据组数。
  • 接下来 Q Q 行,每行包含一个长度为 N N 的字符串 S S

样例评测程序输出格式

如果评测程序正常结束,grader-simplegrader-strict 将向标准输出输出以下信息。

  • 程序正常结束的话,会输出 M M 的值。
  • 运行过程中被判为错误时,以 Wrong Answer [x] 的格式报告并退出。

样例

样例评测输入

4 1
<>[]

样例交互

函数调用 返回值 函数调用 返回值
Memory(4, 0)
Get(1)
<
2015
Memory(4, 2015)
Get(3)
[
3
Memory(4, 3)
Get(2)
>
23
Memory(4, 23)
Get(4)
]
4194303
Memory(4, 4194303)
Get(3)
[
-1

上述过程结束后 grader-simple 会输出 -1

数据范围与提示

对于全部数据,满足 1S100 1 \le |S| \le 100 ,字符串 S S 仅由 <>[] 组成。

本题共有 6 6 个子任务。每个子任务的分数和附加限制如下:

Subtask 附加限制 分数
1 S S 的长度不超过 8 8 10
2 S S 的长度不超过 14 14
3 S S 的长度不超过 24 24 5
4 S S 的长度不超过 30 30
5 字符串 S S 仅由 <> 组成 10
6 无附加限制 60