【题解】2018牛客国庆集训派对Day1 J-Princess Principal 括号匹配

题目在这里
是一个多次询问的括号匹配问题。

如果是平常的括号匹配,我们显然只需要放在栈里面模拟一下就行了。(如果不知道括号匹配怎么做,建议去网上学习一下)

然而这题有多次询问,我们就不能每一次都放进栈里面模拟一下。

那么这题应该怎么做呢?
我们考虑一下,在一个序列中,如果有一段序列是合法的,那么我们就可以把这一段序列从整个序列中删除掉。所以我们只需要将原本序列从头到尾放进栈里面,将匹配的部分删掉,那么剩下的部分就是不匹配的。

至于怎么将匹配的部分删掉,我们定义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;
}

猜你喜欢

转载自blog.csdn.net/KIKO_caoyue/article/details/88011757