Bracket Cost (Codeforces 1750E)
Tags: Greedy, divide and conquer

Daemon Targaryen decided to stop looking like a Metin2 character. He turned himself into the most beautiful thing, a bracket sequence.For a bracket sequence, we can do two kind of operations:  Select one of its substrings$$$^\dagger$$$ and cyclic shift it to the right. For example, after a cyclic shift to the right, "(())" will become ")(()";  Insert any bracket, opening '(' or closing ')', wherever you want in the sequence. We define the cost of a bracket sequence as the minimum number of such operations to make it balanced$$$^\ddagger$$$.Given a bracket sequence $$$s$$$ of length $$$n$$$, find the sum of costs across all its $$$\frac{n(n+1)}{2}$$$ non-empty substrings. Note that for each substring we calculate the cost independently.$$$^\dagger$$$ A string $$$a$$$ is a substring of a string $$$b$$$ if $$$a$$$ can be obtained from $$$b$$$ by deletion of several (possibly, zero or all) characters from the beginning and several (possibly, zero or all) characters from the end.$$$^\ddagger$$$ A sequence of brackets is called balanced if one can turn it into a valid math expression by adding characters $$$+$$$ and $$$1$$$. For example, sequences "(())()", "()", and "(()(()))" are balanced, while ")(", "(()", and "(()))(" are not.

Input: Each test consists of multiple test cases. The first line contains a single integer $$$t$$$ ($$$1 \leq t \leq 10^5$$$) — the number of test cases. The description of test cases follows.The first line of each test case contains a single integer $$$n$$$ ($$$1 \le n \le 2 \cdot 10^5$$$) — the length of the bracket sequence.The second line of each test case contains a string $$$s$$$, consisting only of characters '(' and ')', of length $$$n$$$ — the bracket sequence.It is guaranteed that sum of $$$n$$$ across all test cases does not exceed $$$2 \cdot 10^5$$$.

Output: For each test case, print a single integer — the sum of costs of all substrings of $$$s$$$.

Note: In the first test case, there is the only substring ")". Its cost is $$$1$$$ because we can insert '(' to the beginning of this substring and get a string "()", that is a balanced string.In the second test case, the cost of each substring of length one is $$$1$$$. The cost of a substring ")(" is $$$1$$$ because we can cyclically shift it to right and get a string "()". The cost of strings ")()" and "()(" is $$$1$$$ because its enough to insert one bracket to each of them. The cost of substring ")()(" is $$$1$$$ because we can cyclically shift it to right and get a string "()()". So there are $$$4 + 2 + 2 + 1 = 9$$$ substring of cost $$$1$$$ and $$$1$$$ substring of cost $$$0$$$. So the sum of the costs is $$$9$$$.In the third test case,   "(", the cost is $$$1$$$;  "()", the cost is $$$0$$$;  "())", the cost is $$$1$$$;  ")", the cost is $$$1$$$;  "))", the cost is $$$2$$$;  ")", the cost is $$$1$$$. So the sum of the costs is $$$6$$$.

Sample Inputs:
5
1
)
4
)()(
3
())
5
(((((
10
)(())))())

Sample Outputs:
1
9
6
35
112

Solution (Python):
import io, os
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline

class fenwick(object):

    def __init__(self, n):
        self.n = n
        self.cul = [0] * n
        self.maxd = len(bin(n)) - 3

    def update(self, index, diff):
        i = index
        while i < self.n:
            self.cul[i] += diff
            i += i + 1 & -i - 1

    def getaccu(self, index):
        output = 0
        i = index
        while i >= 0:
            output += self.cul[i]
            i -= i + 1 & -i - 1
        return output

def main(t):
    n = int(input())
    s = input().decode('utf-8')[:n]
    curr = 0
    stack = []
    accuneg = 0
    ans = 0
    mincurr = 0
    maxcurr = 0
    for i in range(n - 1, -1, -1):
        if s[i] == '(':
            curr += 1
            if len(stack) > 0:
                accuneg -= stack.pop()
        else:
            curr -= 1
            stack.append(n - i)
            accuneg += stack[-1]
        ans += accuneg
        mincurr = min(mincurr, curr)
        maxcurr = max(maxcurr, curr)
    fcount = fenwick(maxcurr - mincurr + 1)
    faccu = fenwick(maxcurr - mincurr + 1)
    fcount.update(-mincurr, 1)
    faccu.update(-mincurr, -mincurr)
    curr = 0
    for i in range(n - 1, -1, -1):
        if s[i] == '(':
            curr += 1
        else:
            curr -= 1
        fcount.update(curr - mincurr, 1)
        faccu.update(curr - mincurr, curr - mincurr)
        ans += fcount.getaccu(curr - mincurr) * (curr - mincurr) - faccu.getaccu(curr - mincurr)
    print(ans)
T = int(input())
t = 1
while t <= T:
    main(t)
    t += 1

Solution (Python):
import io, os
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline

class fenwick(object):

    def __init__(self, n):
        self.n = n
        self.cul = [0] * n
        self.maxd = len(bin(n)) - 3

    def update(self, index, diff):
        i = index
        while i < self.n:
            self.cul[i] += diff
            i += i + 1 & -i - 1

    def getaccu(self, index):
        output = 0
        i = index
        while i >= 0:
            output += self.cul[i]
            i -= i + 1 & -i - 1
        return output

def main(t):
    n = int(input())
    s = input().decode('utf-8')[:n]
    fcount = fenwick(2 * n + 1)
    faccu = fenwick(2 * n + 1)
    fcount.update(n, 1)
    faccu.update(n, n)
    curr = 0
    stack = []
    accuneg = 0
    ans = 0
    for i in range(n - 1, -1, -1):
        if s[i] == '(':
            curr += 1
            if len(stack) > 0:
                accuneg -= stack.pop()
        else:
            curr -= 1
            stack.append(n - i)
            accuneg += stack[-1]
        ans += accuneg
        fcount.update(curr + n, 1)
        faccu.update(curr + n, curr + n)
        ans += fcount.getaccu(curr + n) * (curr + n) - faccu.getaccu(curr + n)
    print(ans)
T = int(input())
t = 1
while t <= T:
    main(t)
    t += 1

Solution (Python):
import os, sys
from random import randint, shuffle
from io import BytesIO, IOBase
from collections import defaultdict, deque, Counter
from bisect import bisect_left, bisect_right
from heapq import heappush, heappop
from functools import lru_cache
from itertools import accumulate, permutations
import math
BUFSIZE = 8192

class FastIO(IOBase):
    newlines = 0

    def __init__(self, file):
        self._fd = file.fileno()
        self.buffer = BytesIO()
        self.writable = 'x' in file.mode or 'r' not in file.mode
        self.write = self.buffer.write if self.writable else None

    def read(self):
        while True:
            b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
            if not b:
                break
            ptr = self.buffer.tell()
            (self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
        self.newlines = 0
        return self.buffer.read()

    def readline(self):
        while self.newlines == 0:
            b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
            self.newlines = b.count(b'\n') + (not b)
            ptr = self.buffer.tell()
            (self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
        self.newlines -= 1
        return self.buffer.readline()

    def flush(self):
        if self.writable:
            os.write(self._fd, self.buffer.getvalue())
            (self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

    def __init__(self, file):
        self.buffer = FastIO(file)
        self.flush = self.buffer.flush
        self.writable = self.buffer.writable
        self.write = lambda s: self.buffer.write(s.encode('ascii'))
        self.read = lambda : self.buffer.read().decode('ascii')
        self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
for _ in range(int(input())):
    n = int(input())
    s = input()
    a = [0]
    cur = 0
    for i in range(n):
        if s[i] == '(':
            cur += 1
        else:
            cur -= 1
        a.append(cur)
    n = len(a)
    stack = []
    l = [-1] * n
    for i in range(n):
        while stack and stack[-1][0] >= a[i]:
            stack.pop()
        l[i] = stack[-1][1] if stack else -1
        stack.append([a[i], i])
    stack = []
    r = [n] * n
    for i in range(n)[::-1]:
        while stack and stack[-1][0] > a[i]:
            stack.pop()
        r[i] = stack[-1][1] if stack else n
        stack.append([a[i], i])
    ans = 0
    for i in range(n):
        ans -= a[i] * (i - l[i]) * (r[i] - i)
        ans += a[i]
    a.sort()
    for i in range(n):
        ans += i * a[i]
    print(ans)