题意
给定一个长度为 (n) 的小括号序列,求有多少个位置满足将这个位置的括号方向反过来后使得新序列是一个合法的括号序列。即在任意一个位置前缀左括号的个数不少于前缀右括号的个数,同时整个序列左右括号个数相同。
分析
括号序列显然采取前缀和思想,将('(')记做(1),将(')')记做(-1),记为(sum[])数组,并统计('(')的前缀和,即为(suml[])数组,统计(')')的前缀和,即为(sumr[])数组。
可以发现,对于某一个序列,只能翻转('(')或(')')一种类型,分类进行分析:
((1))('(')比(')')多(2)个,则翻转('(')可以使得(sum[n])变为(0)。考虑翻转第(i)位的('(')会产生的影响。对于(ileq jleq n)来说,所有的(sum[j])都减去(2),所以要保证所有的(sum[])都大于0,即找到(i),有
- (1leq k <i),(sum[k]>=0)
- (i < j leq n),(sum[j]>=2)
- (sum[i]=1)
答案即为(i)~(n)中('(')数量。
((2))('(')比(')')少(2)个,可以通过翻转字符串并将所有的('(')和(')')翻转获得第((1))种情况。也可以通过考虑翻转第(i)位的(')')会产生的影响,对于(ileq jleq n)来说,所有的(sum[j])都加上(2),所以要保证所有的(sum[])都大于0,即找到(i),有
- (1leq k <i),(sum[k]>=0)
- (i < j leq n),(sum[j]>=-2)
- (sum[i]=-1)
答案即为(1)~(i)中的(')')数量。
((3))其他情况输出(0)即可,存在已经为括号序列的字符串,也存在不可能满足条件的字符串。
#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
#define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
#define LL long long
#define int ll
using namespace std;
const int maxn = (ll) 1e6 + 5;
const int mod = 1000000007;
const int inf = 0x3f3f3f3f;
int sum[maxn];
int suml[maxn];
int sumr[maxn];
char s[maxn];
signed main() {
start;
int n;
cin >> n;
cin >> (s + 1);
for (int i = 1; i <= n; ++i) {
suml[i] = suml[i - 1];
sumr[i] = sumr[i - 1];
if (s[i] == '(')
sum[i] = sum[i - 1] + 1, ++suml[i];
else
sum[i] = sum[i - 1] - 1, ++sumr[i];
}
if (sum[n] == 2) {
for (int i = 1; i <= n; ++i)
if (sum[i] < 0) {
cout << 0;
return 0;
}
int l = n;
for (; l > 0; --l)
if (sum[l] == 1)
break;
cout << suml[n] - suml[l];
} else if (sum[n] == -2) {
for (int i = 1; i <= n; ++i)
if (sum[i] < -2) {
cout << 0;
return 0;
}
int l = 1;
for (; l <= n; ++l)
if (sum[l] == -1)
break;
cout << sumr[l];
} else
cout << 0;
return 0;
}