【LOJ#3005】Limited Memory

题目

题目链接: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))

注意当 (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);
	}
}
原文地址:https://www.cnblogs.com/stoorz/p/15039927.html