正题
题目链接:https://loj.ac/p/3005
题目大意
有一个长度为nnn的括号串SSS,其中包括[]和<>两种括号类型,一个合法的括号串要求同类型的括号一一对应。
你每次可以询问SSS中的一个字符并且传递一个[0,222)[0,2^{22})[0,222)的数字到下一次。
你的程序每次只知道字符串长度nnn和上一次传递过来的数字(最开始时是000),你需要在150001500015000次内得到这个字符串是否为一个合法括号串。
1≤n≤1001\leq n\leq 1001≤n≤100
解题思路
很有趣的题目。
我们需要知道的信息只有这个括号串是否合法,考虑怎么把什么信息编码进[0,222)[0,2^{22})[0,222)内。
考虑这样一个算法流程,我们先找到一个 ‘[’ 或者 ‘<’,然后开始往后找它对应的那个括号。
此时一个合法括号串有两种可能,
- 下一个是和它对应的括号,此时这个部分的匹配就结束了。
- 下一个也是 ‘[’ 或者 ‘<’ ,此时我们需要去匹配这个新的左括号之后,知道它右括号的位置,在继续从这个位置去匹配前面那个左括号。
也就是考虑当一个匹配结束的时候,假设位置为yyy,考虑怎么返回到前一个还未匹配的左括号xxx那里。显然[x+1,y][x+1,y][x+1,y]这一段括号序列都合法了,也就是括号类型也一一对应了,那么我们直接往前跑,遇到一个左括号就−1-1−1,一个右括号就+1+1+1,那第一个和为−1-1−1的位置就是我们需要的位置,同时我们还需要带一个位置yyy的信息回去。
那么现在我们需要储存的信息就是当前的位置AAA,带回去的位置信息BBB,当前的和CCC,还有目前的状态DDD。
状态分444种
- 寻找新的左括号中
- 往回走找之前的左括号中
- 匹配左括号 [ 中
- 匹配左括号 < 中
这样的状态数就是4×n3≤2224\times n^3\leq 2^{22}4×n3≤222,可以通过本题。
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;
}