本文受洛谷第一个题解启发
怎么解决这个题目?
不要一上来就去想拿满分
要研究数据规模,发现有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<bits/stdc++.h>
#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