HDU5357 Easy Sequence (栈的应用)

/**
E - Easy Sequence

题意:给出一个左右括号序列,设ANSi是第i个括号所在的有效括号对的数量,有效括号对指的是(),()(),(())这样
的形式要求 sum { ANSi * i % mod | 1 <= i <= n }, 注意是求每个i先取模之后的和,不是所有和取模

思路:一开始看成是求出所有和再取模,直接求贡献去了然后WA,首先如果一个左括号是在一个有效括号对内,它
有唯一一个右括号与之配对,所以可以用栈找出所有有效括号对,而且对于一个括号如果包含在某个有效括号对内,
这个最小的有效括号对是唯一的,那么对于一个有效括号对(待讨论的用[]表示),左括号和右括号的ans是一样的,
只讨论左括号,那么(..)(..)[..](..)(..),这样的对ans提供(左边括号数 + 1) * (右边括号数 + 1) = x1,(([..]))
这样的提供内层的ans' = x2,所以他的ans = x1 + x2,x1也可以用栈记录这些区间求得,对于x2记录每个括号的父
括号的ans值即可
**/

#include<bits/stdc++.h>
typedef long long ll;
const int maxn = 1e6 + 10;
const ll mod = 1e9 + 7;
using namespace std;

typedef pair<int, int> pa;
char str[maxn];
int T, stk[maxn], pre[maxn], nxt[maxn];
ll suml[maxn], sumr[maxn], rec[maxn];
pa res[maxn];

int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%s", str + 1);
        int len = strlen(str + 1), x = 0, ind, tot = 1;
        ll ans = 0;
        for(int i = 1; i <= len; i++) {
            char c = str[i]; ind = i; nxt[i] = pre[i] = 0;
            if(c == '(') { stk[x++] = i; continue; }
            if(x && str[stk[x - 1]] == '(') {
                x--; ind = stk[x];
                int l = ind, r = i;
                nxt[l] = r;
                while(tot > 1 && res[tot - 1].first >= l && res[tot - 1].second <= r) {
                    tot--; pa now = res[tot];
                    pre[now.first] = l;
                    if(now.second == res[tot + 1].first - 1) sumr[tot] = sumr[tot + 1] + 1;
                    else sumr[tot] = 1;
                    ll val = suml[tot] * sumr[tot];
                    rec[now.first] = val;
                }
                if(tot > 1 && res[tot - 1].second == l - 1) suml[tot] = suml[tot - 1] + 1;
                else suml[tot] = 1;
                res[tot++] = pa(l, r); res[tot] = pa(len + len, len + len);
            } else stk[x++] = i;
        }
        for(int i = tot - 1; i >= 1; i--) {
            pa now = res[i], nxt = res[i + 1];
            if(now.second == nxt.first - 1) sumr[i] = sumr[i + 1] + 1;
            else sumr[i] = 1;
            ll val = suml[i] * sumr[i];
            rec[now.first] = val;
        }
        for(int i = 1; i <= len; i++) {
            if(str[i] == ')' || !nxt[i]) continue;
            ll x = i, y = nxt[i];
            rec[i] = (rec[i] + rec[pre[i]]) % mod;
            ans += x * rec[i] % mod;
            ans += y * rec[i] % mod;
        }
        printf("%lld\n", ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值