题目描述
阿尔比恩王国(the Albion Kingdom)潜伏着一群代号“白鸽队(Team White Pigeon)”的间谍。在没有任务的时候,她们会进行各种各样的训练,比如快速判断一个文档有没有语法错误,这有助于她们鉴别写文档的人受教育程度。
这次用于训练的是一个含有n个括号的文档。括号一共有mm种,每种括号都有左括号和右括号两种形式。我们定义用如下的方式定义一个合法的文档:
1.一个空的字符串是一个合法的文档。
2.如果A,B都是合法的文档,那么AB也是合法的文档。
3.如果S是合法的文档,那么aSb也是合法的文档,其中a,b是同一种括号,并且a是左括号,b是右括号。
现在给出q个询问,每次询问只考虑文档第ll至rr个字符的情况下,文档是不是合法的。
输入
第一行两个整数n,m,q(1≤n,m,q≤106)。
第二行有n个空格隔开的整数x,第i个整数xi(0≤xi<m∗2)代表文档中的第i个字符是第⌊x/2⌋种括号,且如果xi是偶数,它代表一个左括号,否则它代表一个右括号。
接下来q行,每行两个空格隔开的整数l,r(1≤l≤r≤n),代表询问第l至r个字符构成的字符串是否是一个合法的文档。
输出
输出共q行,如果询问的字符串是一个合法的文档,输出"Yes",否则输出"No"。
样例输入
6 4 3 0 2 3 1 4 7 1 4 1 5 5 6
样例输出
Yes No No
我的思路是每次读入一个括号,用括号序列的思路,如果栈顶和当前括号不能匹配,则将当前括号压入栈;如果能匹配,那么就将栈顶元素弹出。并且每次读入处理完之后都将当前栈顶元素存入一个ans数组内。很明显,如果l位置与r位置是匹配的括号,并且从l位置到r位置中间均为合法序列,那么从l+1位置到r-1位置的括号序列必然合法,也就是说中间这段的括号序列左半边所对应的右半边必然也在这段范围之内,那么我们在预处理的时候一定在l之后将左括号压入了栈,并在遇到左括号所对应的右括号时从栈中弹出,那么r位置与l-1位置时栈顶元素相同,即ans[l]==ans[r-1]。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
int top;
int z[maxn],st[maxn],ans[maxn];
int main()
{
int n,m,q,l,r;
scanf("%d%d%d", &n, &m, &q);
for (int i = 1; i <= n; ++i)
scanf("%d", &z[i]);
for (int i = 1; i <= n; ++i)
{
if (!top || z[st[top]] / 2 != z[i] / 2 || z[i] != z[st[top]] + 1) //如果当前位置与栈顶位置的括号不匹配或者不合法
st[++top] = i;
else //如果当前位置与栈顶位置的括号相匹配并且合法
--top;
ans[i] = st[top]; //存下栈顶位置
}
while (q--)
{
scanf("%d%d", &l, &r);
if (ans[r] == ans[l - 1])
puts("Yes");
else
puts("No");
}
return 0;
}