【题目描述】
【题解】
- 是时候讨论一下我在考场上是怎么将这道题写挂的了
- 初看这道题毫无思路,先看看部分分吧
- 一条链的情况?设k[i]表示前i个括号的方案数
- 显然\(k[i]=k[i-1]+\)以i结尾的合法子串个数
- 考虑求\(a[i]\)表示以\(i\)结尾的合法子串个数,显然如果第\(i\)个字符是\(‘('\),\(a[i]=0\)
- 否则,看第\(i-1\)个字符,如果是\(‘(’\),则\(a[i]=a[i-2]\),否则就跳到与\(i-1\)匹配的\(b[i-1]\)处看\(b[i-1]-1\)是否是\('('\),如果不是,就再往前匹配······依次类推即可
- 然而,我在考场上时,居然脑抽,只往前匹配了一次,并且就这样还通过了大样例···
//惨痛回忆
//d[i]=1表示是左括号,=-1表示是右括号
for(int i=1;i<=n;++i){
if(d[i]==1){
k[i]=k[i-1];
continue;
}
if(i==1) continue;
if(d[i-1]==1){
b[i]=i-1;
a[i]=a[i-2]+1;
}
else if(d[b[i-1]-1]==1) a[i]=a[b[i-1]-2]+1,b[i]=b[i-1]-1;
k[i]=k[i-1]+a[i];
}
//正解
for(int i=1;i<=n;++i){
if(d[i]==1){
k[i]=k[i-1];
continue;
}
if(i==1) continue;
int now=i-1;
while(d[now]!=1&&now)
now=b[now]-1;
if(now){
a[i]=a[now-1]+1;
b[i]=now;
}
k[i]=k[i-1]+a[i];
}
- 正解,则只需要将链中通过-1向前推改为通过父子关系推即可
【代码】
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=5e5+10;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*f;
}
int n,d[N],fa[N],a[N],b[N],k[N],ans;
signed main(){
n=read();
for(int i=1;i<=n;i++){
char ch=getchar();
while(ch!='('&&ch!=')') ch=getchar();
if(ch=='(') d[i]=1;
else d[i]=-1;
}
for(int i=2;i<=n;i++)
fa[i]=read();
for(int i=1;i<=n;i++){
if(i==1) continue;
if(d[i]==1) k[i]=k[fa[i]];
else{
int now=fa[i];
while(d[now]!=1&&now)
now=fa[b[now]];
if(now){
a[i]=a[fa[now]]+1;
b[i]=now;
}
k[i]=k[fa[i]]+a[i];
}
ans=ans^(i*k[i]);
}
cout<<ans<<endl;
return 0;
}