题目在这里
是一个多次询问的括号匹配问题。
如果是平常的括号匹配,我们显然只需要放在栈里面模拟一下就行了。(如果不知道括号匹配怎么做,建议去网上学习一下)
然而这题有多次询问,我们就不能每一次都放进栈里面模拟一下。
那么这题应该怎么做呢?
我们考虑一下,在一个序列中,如果有一段序列是合法的,那么我们就可以把这一段序列从整个序列中删除掉。所以我们只需要将原本序列从头到尾放进栈里面,将匹配的部分删掉,那么剩下的部分就是不匹配的。
至于怎么将匹配的部分删掉,我们定义dp[i]表示第i个括号的匹配处。举个例子,有一个序列是0 2 3,显然2和3是匹配的,dp[1] = 1,dp[2] = 2,dp[3] = 1,我们判断dp[1]==dp[3],就可以知道第2,3两个括号是匹配的了。
下面我们看一个括号比较多的序列:
6 | 0 | 0 | 2 | 3 | 1 | 1 | 4 | 7 |
---|---|---|---|---|---|---|---|---|
dp[1] = 1 | dp[2] = 2 | dp[3] = 3 | dp[4] = 4 | dp[5] = 3 | dp[6] = 2 | dp[7] = 1 | dp[8] = 8 | dp[9] = 9 |
如果明白了上面表格的含义,那么这个题目就轻而易举的AC啦。
我们只需要预处理这个表格,判断的时候就是dp[l-1] == dp[r]。
下面是代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+7;
int a[maxn];
int n,m,q;
stack<int> s;
int dp[maxn];
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++) scanf("%d",a+i);
for(int i=1;i<=n;i++)
{
if(!s.empty())
{
int u = s.top();
if(a[u]+1==a[i] && (a[i]%2))
{
s.pop();
if(s.empty())
{
dp[i] = 0;
}
else
{
dp[i] = s.top();
}
}
else
{
s.push(i);
dp[i] = s.top();
}
}
else
{
s.push(i);
dp[i] = s.top();
}
}
while(q--)
{
int l,r;
scanf("%d%d",&l,&r);
if(dp[l-1]==dp[r]) printf("Yes\n");
else printf("No\n");
}
return 0;
}