题目链接: https://nanti.jisuanke.com/t/24214
可爱的PLY有一个长度为nn的括号序列a[1-n]a[1−n](即仅由字符'('与字符')'组成的字符串)。某一天,PLY的心上人Gay王·齐齐去PLY家玩耍,他对这个括号序列很是喜欢,PLY说只要齐齐能答对一个问题就把这个括号序列送给齐齐当做定情信物:在这个括号序列之中,存在多少个不同的位置pp,只将a[p]a[p]处的括号翻转后(即若原来a[p]a[p]为左括号则变为右括号,原来为右括号则变为左括号),整个括号序列是一个合法的括号序列。齐齐请求你的帮助!
合法括号序列指的是满足以下条件之一的括号序列:
- 空串""是合法括号序列。
- 若"SS"是合法括号序列,则"(S)(S)"也是合法括号序列。
- 若"S1S"与"S2"是合法括号序列,则"S1S2"也是合法括号序列。
输入格式
输入第一行1个整数T表示数据组数。
对于每组数据:
第一行1个整数n(1 <= n <= 1e5)表示括号序列长度。
第二行1个长度为n的括号序列a[1--n]。
输出格式
对于每组数据,输出1个整数表示满足条件的pp的数目。
样例输入
3 1 ( 2 () 6 (())))
样例输出
0 0 3
思路: 进行括号匹配,如果满足只翻转一个括号就能够使得这个序列成为合法序列,那么剩下的匹配失败的括号必定是剩下两个。
一共有三种情况:1、"((" 2、"))" 3、")("。 很明显第三种情况不能满足题意。
第一种情况我们只需要计算包括右边那个括号在内的序列右边所有的右括号数目,就可以得到答案。
第二种情况同理计算左边的左括号在序列左边所有的左括号数目。
输出即可。
官方题解:将左括号'('视为+1,右括号')'视为-1,则序列合法等价于所有前缀和非负且最后为零。求出前缀和后预处理左右的最小值,枚举翻转位置判断可行性即可。
代码如下:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 char str[100010]; 5 int num[100010]; 6 int main() 7 { 8 int T; 9 scanf("%d",&T); 10 while(T--) 11 { 12 int n; 13 scanf("%d",&n); 14 scanf("%s",str); 15 vector<int> v; 16 stack<int> s; 17 for(int i=0; i<n; i++) 18 { 19 if(str[i] == '(') 20 s.push(i); 21 else if(!s.empty()) 22 { 23 s.pop(); 24 } 25 else 26 { 27 v.push_back(i); 28 } 29 } 30 while(!s.empty()) 31 { 32 int t = s.top(); 33 v.push_back(t); 34 s.pop(); 35 } 36 sort(v.begin(),v.end()); 37 int ans = 0; 38 if(v.size() != 2 || str[v[0]] == ')' && str[v[1]] == '(') 39 ; 40 else if(str[v[0]] == ')') 41 { 42 for(int i=v[0]; i>=0; i--) 43 if(str[i] == ')') 44 ans++; 45 } 46 else 47 { 48 for(int i=v[1]; i<n; i++) 49 if(str[i] == '(') 50 ans++; 51 } 52 printf("%d ",ans); 53 } 54 return 0; 55 }