题目
题目链接:https://loj.ac/p/3005
由于题目太长了还不能复制,这里就不放题面了(
思路
(nleq 100),询问次数是 (15000),那么可以枚举每一个位置的字符,每次暴力 (O(n)) 找它匹配的字符。
只能记录一个 (22) 位的二进制数。那么肯定是要把若干信息状压后扔进去。
我们记目前寻找匹配的位置 (l),以及现在枚举到的位置 (r),括号匹配肯定需要用一个栈来维护,但是因为只需要匹配位置 (l) 的字符,其他字符是否匹配都无关,所以我们也只需要记录栈的大小 (top)。最后再记录位置 (l) 的字符是 <>
或 []
的哪一种。
(l,r,top) 最大都是 (100),在二进制下最多是 (7) 位。再加上我们记录了第 (l) 个字符,恰好需要用到 (22) 位。
由于目前需要寻找匹配的字符 (l) 有可能是左括号或者右括号,因为匹配的本质是一样的,所以我们只考虑 (l) 是左括号(<
或 [
) 的情况。
不断重复以下过程:
- 如果 (l>n),返回
-1
。 - 如果 (r>n),返回
-2
。 - 如果 (l=r),询问
Get(l)
,返回 ((l,r+1,1,id)),其中 (id) 如果 (s[l]) 是<
则为 (0),否则为 (1)。 - 如果 (l<r),询问
Get(r)
,如果字符是<
或[
则让 (top) 加一,否则让 (top) 减一。- 如果操作后 (top) 为 (0),那么如果 (s[r]) 和 (id) 匹配,那么返回 ((l+1,l+1,0,0)),否则返回
-2
。 - 如果操作后 (top) 不为 (0),那么返回 ((l,r+1,top,id))。
- 如果操作后 (top) 为 (0),那么如果 (s[r]) 和 (id) 匹配,那么返回 ((l+1,l+1,0,0)),否则返回
注意当 (s[l]) 是 >
或 ]
的时候需要完全反过来搞。
时间复杂度 (O(n^2)),操作次数显然是严格小于 (n^2) 的。
代码
#include <bits/stdc++.h>
#include "memory.h"
using namespace std;
int calc(int l,int r,int top,int id)
{
return (l<<15)+(r<<8)+(top<<1)+id;
}
int Memory(int n,int m)
{
// LLLLLLLRRRRRRRTTTTTTTC
if (!m) return calc(1,1,0,0);
int l=(m>>15),r=(m>>8)&127,top=(m>>1)&127;
if (l>n) return -1;
if (!r || r>n) return -2;
char ch=Get(r);
if (l==r)
{
if (ch=='[' || ch=='<') return calc(l,r+1,1,ch=='[');
if (ch==']' || ch=='>') return calc(l,r-1,1,ch==']');
}
if (l<r)
{
if (ch=='<' || ch=='[') top++;
if (ch=='>' || ch==']') top--;
if (!top)
{
if ((m&1) && ch=='>') return -2;
if (!(m&1) && ch==']') return -2;
return calc(l+1,l+1,0,0);
}
return calc(l,r+1,top,m&1);
}
if (l>r)
{
if (ch=='>' || ch==']') top++;
if (ch=='<' || ch=='[') top--;
if (!top)
{
if ((m&1) && ch=='<') return -2;
if (!(m&1) && ch=='[') return -2;
return calc(l+1,l+1,0,0);
}
return calc(l,r-1,top,m&1);
}
}