蜗蜗的括号序列

题目传送门

整体思路:前缀和

正解
括号序列一般使用栈配合解决的。那么这道题目要我们求价值,该怎么办呢

1.非法括号序列
非法的括号序列可以用总共的减去合法的,所以难点在于合法
2.合法括号序列
首先,我们可以遍历字符串。如果遇到左括号,就把下标压到栈里面。如果遇到右括号,就把栈顶弹出来,然后计算贡献
对于当前遍历到的下标j和栈顶下标i,不难发现,如果i和j可以配在一起,说明i+1~j-1是一个合法的括号序列,也就是说,中间这一段是没有一个下标可以和j匹配上。
当然,如果A是一个合法的括号序列,B是一个合法的括号序列。那么AB也是一个合法的括号序列,这个时候还是有很多贡献的。
我们具体看一下贡献的式子
设有k个左括号可以和j匹配,分别是\(i_1,i_2,i_3……,i_k\)那么贡献就是\(a_j*k-a_{i_1}-a_{i_2}-a_{i_3}-……-a_{i_k}\)
但是也现在有有两个问题了
1.怎么求后面一大坨
我们可以开一个sum数组
\(sum_i\)表示以i为结尾的后面一大坨
如何转移?回到刚刚的问题,也就是说对于\(sum_j\)来说,它等于\(sum_{i-1}+a[i]\)
这个问题解决了
2.怎么求出k
我们可以模仿上面的思路开一个cnt数组
\(cnt_i\)表示以i为结尾有多少个括号可以和它配上。同样的,转移方程为\(cnt_j=cnt_{i-1}+1\)

最后,将合法加一,然后遍历完了再把不合法的贡献加上,整个题就结束了

代码如下

#include<bits/stdc++.h>
using namespace std;
#define ll long long

const int N=5e5+10;
int n,a[N],cnt[N];
ll sum[N];
char s[N];

int main(){
    cin.tie(0)->sync_with_stdio(0);
    cin>>n>>s+1;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    stack<int> stk;
    long long ans=0,le=0;
    for(int i=1;i<=n;i++){
        if(s[i]=='('){
            stk.push (i);
        }else{
            int j=stk.top();
            stk.pop();
            cnt[i]=cnt[j-1]+1;
            sum[i]=sum[j-1]+a[j];
            le+=cnt[i];
            ans+=1LL*cnt[i]*a[i]-sum[i];
        }
    }
    ans+=1LL*n*(n+1)/2-le;
    cout<<ans<<endl;
}
posted @ 2026-01-24 11:57  zhangruotian_Max  阅读(0)  评论(0)    收藏  举报