Loj#3005-「JOISC 2015 Day 4」Limited Memory【交互题】

正题

题目链接:https://loj.ac/p/3005


题目大意

有一个长度为\(n\)的括号串\(S\),其中包括[]和<>两种括号类型,一个合法的括号串要求同类型的括号一一对应。

你每次可以询问\(S\)中的一个字符并且传递一个\([0,2^{22})\)的数字到下一次。

你的程序每次只知道字符串长度\(n\)和上一次传递过来的数字(最开始时是\(0\)),你需要在\(15000\)次内得到这个字符串是否为一个合法括号串。

\(1\leq n\leq 100\)


解题思路

很有趣的题目。

我们需要知道的信息只有这个括号串是否合法,考虑怎么把什么信息编码进\([0,2^{22})\)内。

考虑这样一个算法流程,我们先找到一个 '[' 或者 '<',然后开始往后找它对应的那个括号。

此时一个合法括号串有两种可能,

  1. 下一个是和它对应的括号,此时这个部分的匹配就结束了。
  2. 下一个也是 '[' 或者 '<' ,此时我们需要去匹配这个新的左括号之后,知道它右括号的位置,在继续从这个位置去匹配前面那个左括号。

也就是考虑当一个匹配结束的时候,假设位置为\(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;
}
posted @ 2022-06-15 11:24  QuantAsk  阅读(94)  评论(2编辑  收藏  举报