csp-s2019 括号树(55分)

本文受洛谷第一个题解启发

怎么解决这个题目?

不要一上来就去想拿满分

要研究数据规模,发现有55分是单链,所以先研究单链吧

举特例研究

例1.n=4    ( ) ( )——从1开始计数

先看每一个括号的贡献 【 重要注解——   c[i]贡献值:以结点i结尾但头不固定的合法子串个数】

c[1..4]=0,1,0,2

再用前缀和

从根结点到结点i的合法括号子串数为0,1,1,3

例2.n=6    (( ) )( )——从1开始计数

c[1..6]=0,0,1,1,0,2

再用前缀和

从根结点到结点i的合法括号子串数为0,0,1,3,3,6

写了例1,例2,下面总结下

写出每一个括号的贡献,

如果是右括号,则看前面有没有与之匹配的左括号,若有,则它有贡献,然后它的值应该是与它匹配的左括号的父结点贡献值+1

如果是左括号,则贡献是0

子串括号数用前缀和

接下来,怎么处理括号匹配的问题呢?

用栈——这是常规题目了

左括号的位置圧入栈

右括号,如果栈空,则这个右括号不用理睬,如果栈不空,则栈顶的左括号与它匹配,处理好后,一定要把栈顶的左括号弹出栈

//-----按照链处理,争取拿55分
#include
#define ll long long
#define maxn 500005
using namespace std;
int n;
char c[maxn];  //读入链 
ll lst[maxn],sum[maxn],ans;   //lst=last当前 
int s[maxn],top;   //用数组模拟栈,栈指针
int main()
{
	scanf("%d",&n);
	scanf("%s",c+1);
	for(int i=2;i<=n;i++)
	{
		int f;
		scanf("%d", &f);
	}
	for(int i=1;i<=n;i++)
	{
		if(c[i]==')')
		{
			if(top) //栈不空 
			{
				int t=s[top];
				lst[i]=lst[t-1]+1;  //当前右括号的贡献=与之匹配的栈顶左括号的父结点的贡献+1 
				top--; //与当前匹配的左括号弹出 
			}		
		}
		else if(c[i]=='(')s[++top]=i; //压入左括号 
		sum[i]=sum[i-1]+lst[i]; //前缀和 
	}
	for(int i=1;i<=n;i++)
		ans^=sum[i]*(ll)i;
	printf("%lld",ans);
	return 0;
}

在提交前,务必举些特例验证!

提供两个样例

1)()()(())

贡献值依次为01020013

2)(()))()

贡献值依次为0001102

你可能感兴趣的:(c++)