題目描述
可愛的PLY有一個長度爲nn的括號序列a[1-n]a[1−n](即僅由字符'('與字符')'組成的字符串)。某一天,PLY的心上人Gay王·齊齊去PLY家玩耍,他對這個括號序列很是喜歡,PLY說只要齊齊能答對一個問題就把這個括號序列送給齊齊當做定情信物:在這個括號序列之中,存在多少個不同的位置pp,只將a[p]a[p]處的括號翻轉後(即若原來a[p]a[p]爲左括號則變爲右括號,原來爲右括號則變爲左括號),整個括號序列是一個合法的括號序列。齊齊請求你的幫助!
合法括號序列指的是滿足以下條件之一的括號序列:
- 空串""是合法括號序列。
- 若"SS"是合法括號序列,則"(S)(S)"也是合法括號序列。
- 若"S_1S1"與"S_2S2"是合法括號序列,則"S_1S_2S1S2"也是合法括號序列。
輸入格式
輸入第一行11個整數TT表示數據組數。
對於每組數據:
第一行11個整數nn(1 \leq n \leq 10^{5}1≤n≤105)表示括號序列長度。
第二行11個長度爲nn的括號序列a[1-n]a[1−n]。
輸出格式
對於每組數據,輸出11個整數表示滿足條件的pp的數目。
樣例輸入
3 1 ( 2 () 6 (())))
樣例輸出
0 0 3
題解:若能湊對,則把括號串正向掃描一遍計數,遇到 ( 就+1,遇到 ) 就-1,如果小於0了就說明此串不行,再反向掃描一遍也是同樣的原理;
每個括號改變之後重新掃描肯定超時,那就記錄下來正向掃描從i到最後的最小值和反向掃描從i到最開始的最小值,反轉括號之後掃描值發生變動+2或-2,如果最小值變動後仍不小於0,此串就是可以的。
代碼:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<cstdlib>
#include<algorithm>
using namespace std;
char a[100005];
int pos[100005],neg[100005];
int minzheng[100005],minfan[100005];
int main()
{
int t;
int n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
getchar();
int sum1 = 0;
int mmp=0;
//輸入並正向掃描
for(int i = 0;i < n;++i)
{
scanf("%c",&a[i]);
if(a[i] == '(')
{
pos[i] = ++sum1;
mmp++;
}
else
pos[i] = --sum1;
}
int minn=1e8;
//正向掃描從i開始的最小值
for(int i = n-1;i>=0;--i)
{
if(pos[i]<minn)
minn=pos[i];
minzheng[i]=minn;
}
//如果是奇數個必然不可以
if(n%2)
{
cout<<"0"<<endl;
continue;
}
//反向掃描
int sum2=0;
for(int i = n-1;i >= 0;--i)
{
if(a[i] == ')')
neg[i] = ++sum2;
else
neg[i] = --sum2;
}
//反向掃描時從i到0的最小值
int minx=1e8;
for(int i = 0;i < n;++i)
{
if(neg[i] < minx)
minx = neg[i];
minfan[i] = minx;
}
char c;
int u;
//如果正反括號數量相等,咋變也白費
if(mmp==n-mmp)
{
cout<<"0"<<endl;
continue;
}
//優化,只能是多的括號變
if(mmp>n-mmp)
{
c='(';
u=-2;
if(mmp-n+mmp!=2)
{
cout<<"0"<<endl;
continue;
}
}
else
{
c=')';
u=2;
if(mmp-n+mmp!=-2)
{
cout<<"0"<<endl;
continue;
}
}
//循環逐個判定
int num=0;
for(int i = 0;i < n;++i)
{
bool judge=1;
if(a[i]!=c)
continue;
if(minzheng[i]+u<0||minfan[i]-u<0)
judge=0;
if(judge)
num++;
}
//輸出結果
cout<<num<<endl;
}
return 0;
}