Loj#3005-「JOISC 2015 Day 4」Limited Memory【交互题】
正题
题目大意
有一个长度为\(n\)的括号串\(S\),其中包括[]和<>两种括号类型,一个合法的括号串要求同类型的括号一一对应。
你每次可以询问\(S\)中的一个字符并且传递一个\([0,2^{22})\)的数字到下一次。
你的程序每次只知道字符串长度\(n\)和上一次传递过来的数字(最开始时是\(0\)),你需要在\(15000\)次内得到这个字符串是否为一个合法括号串。
\(1\leq n\leq 100\)
解题思路
很有趣的题目。
我们需要知道的信息只有这个括号串是否合法,考虑怎么把什么信息编码进\([0,2^{22})\)内。
考虑这样一个算法流程,我们先找到一个 '[' 或者 '<',然后开始往后找它对应的那个括号。
此时一个合法括号串有两种可能,
- 下一个是和它对应的括号,此时这个部分的匹配就结束了。
- 下一个也是 '[' 或者 '<' ,此时我们需要去匹配这个新的左括号之后,知道它右括号的位置,在继续从这个位置去匹配前面那个左括号。
也就是考虑当一个匹配结束的时候,假设位置为\(y\),考虑怎么返回到前一个还未匹配的左括号\(x\)那里。显然\([x+1,y]\)这一段括号序列都合法了,也就是括号类型也一一对应了,那么我们直接往前跑,遇到一个左括号就\(-1\),一个右括号就\(+1\),那第一个和为\(-1\)的位置就是我们需要的位置,同时我们还需要带一个位置\(y\)的信息回去。
那么现在我们需要储存的信息就是当前的位置\(A\),带回去的位置信息\(B\),当前的和\(C\),还有目前的状态\(D\)。
状态分\(4\)种
- 寻找新的左括号中
- 往回走找之前的左括号中
- 匹配左括号 [ 中
- 匹配左括号 < 中
这样的状态数就是\(4\times n^3\leq 2^{22}\),可以通过本题。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include "memory.h"
using namespace std;
//D 0:往后寻找新的 1:往前找 2:前面是[ 3:前面是(
//A:目前所在的位置 B:之前反回来的位置 C:和
int Memory(int N, int M) {
int A=M%100,B=M/100%100,C=M/10000%100,D=M/1000000;
if(A>=N)return 0;
char c=Get(A+1);
if(!D){
if(A==N-1)return -2;
if(c=='>'||c==']')return -2;
if(c=='[')return (A+1)+2000000;
if(c=='<')return (A+1)+3000000;
}
else if(D==1){
if(c=='<'||c=='[')C--;
else C++;
if(C==-1){
if(B==N-1)return -2;
return (B+1)+2000000+1000000*(c=='<');
}
if(A==0&&B==N-1)return -1;
if(A==0)return B+1;
return (A-1)+B*100+C*10000+1000000;
}
else if(D==2){
if(c==']')return A+A*100+1000000;
else if(c=='>')return -2;
if(A==N-1)return -2;
return (A+1)+2000000+1000000*(c=='<');
}
else{
if(c=='>')return A+A*100+1000000;
else if(c==']')return -2;
if(A==N-1)return -2;
return (A+1)+2000000+1000000*(c=='<');
}
return M;
}