题目
题解
本人语言能力有限,看代码可能更好理解,以下题解可跳过
此题就是一系列恶心人的情况,你一一讨论出来就可以过了。
PS:我的方法好像跟其他做法不太一样,各位请选择观看
一般思路肯定就是一直搜下去。
本人认为本题的最大难点就是它成功地匹配了一个,对总和ki的贡献值。
首先看这一情况(())
,这我们只能看作一个整体,因为在后面再加入一个()
,它也不能用内部的括号
新增的合格括号则对答案的贡献与之前连续整体的数量有关,这个不好描述
看图(()))(()()(
此时如果多加一个)
则对总和ki的贡献值是3,算上它本身,还有前面两个括号组可以与它组合合法括号串
而最前面的一堆合法括号串被隔开,显然不能够对答案进行贡献。
确实很难描述,建议手动推一下
我们拿pre数组表示离i结点最近是(
且未被匹配的祖先(或者它本身)
num[i]表示遍历到i,当前连续整体的个数
sum[i]则统计当前结点答案
如果当前结点是(
,sum就是父亲结点的值
如果之前并不是整体,那么这个时候前面暂时就没有连续的点。
如果是整体,那么num应该加1
如果当前结点是)
如果前面没有左括号,则sum,与num承接父亲
如果有,那么sum就是要加上1,并且连续整体的数量
同时pre,num数组需特殊更新(主要是实在描述不出来了,我太逊了)
至于判断是否判断整体,我们用了flag。
整体是个bfs。
我的代码也是被很多大佬吊打
代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<queue>
#include<set>
#define N 500005
using namespace std;
struct node{
int u,fg;
node(){};
node(int U,int F){
u = U,fg = F;
}
};
int n,fa[N],pre[N],num[N];
long long ans,sum[N];
char c[N];
vector<int>G[N];
void bfs(){
queue<node>Q;
Q.push(node(1,0));
while (!Q.empty()){
int u = Q.front().u,flag = Q.front().fg;
Q.pop();
for (int i = 0;i < G[u].size();i ++){
int v = G[u][i];
bool flag1 = 0;
if (c[v] == '('){
sum[v] = sum[u];
pre[v] = v;
if (!flag || c[u] == '(')
num[v] = 0;
else if (flag)
num[v] = num[u] + 1;
}
else {
if(!pre[u]){
sum[v] = sum[u];
num[v] = num[u];
}
else {
sum[v] = sum[u] + 1 + num[pre[u]];
pre[v] = pre[fa[pre[u]]];
flag1 = 1;
num[v] = num[pre[u]];
}
}
ans = ans ^ (sum[v] * v);
Q.push(node(v,flag1));
}
}
}
int main(){
scanf ("%d
",&n);
for (int i = 1;i <= n;i ++)
scanf ("%c",&c[i]);
for (int i = 2;i <= n;i ++){
scanf ("%d",&fa[i]);
G[fa[i]].push_back(i);
}
if (c[1] == '(')
pre[1] = 1;
bfs();
printf("%lld
",ans);
}
}
结语
自己能力不强,考场做的题现在都推不出来。总之一句话:我菜炸了。
自己真的是个菜逼,明明很显然的代码却是打得很复杂。