题意
给你n个包含’(‘与’)’的字符串,可以将这些字符串任意排序,求所有排序中,子序列是正规括号序列的最大长度。
题解
参考大佬https://blog.csdn.net/ACTerminate/article/details/81171799
首先我们对所有的字符串找到通过stack找到所有的串内正规括号子序列,之后剩下的串只有三种可能:
1. 只包含’(’
2. 先是一串’)’然后再是一串’(’
3. 只包含’)’
然后,按照第一类,第二类,第三类的顺序放置串。对于第二类内的排序,首先按照’(‘个数贡献正负排序,’)’个数小于’(‘个数则贡献为正,贡献是正的则排前面。然后正贡献的串,我们按照’)’个数从小到大排。负贡献的串,我们按照’(‘个数从大到小排。对于排序完的串,我们从前往后模拟记录一下即可。
注意:对正贡献串排序的时候因为a<0,所以应该return x.a>y.a
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const int maxn=200005;
const double eps=1e-8;
const double PI = acos(-1.0);
#define lowbit(x) (x&(-x))
struct node
{
ll a,b;
};
bool operator <(node x,node y)
{
if(x.a+x.b>=0&&y.a+y.b>=0)
{
return x.a>y.a;
}
else if(x.a+x.b>=0)
{
return 1;
}
else if(y.a+y.b>=0)
{
return 0;
}
else
{
return x.b>y.b;
}
}
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0);
int t,n;
cin>>t;
while(t--)
{
vector<node> v1,v2,v3;
stack<char> st;
cin>>n;
ll ans=0;
for(int i=0; i<n; i++)
{
char s[100005];
cin>>s;
for(int j=0; j<strlen(s); j++)
{
if(s[j]=='(')
st.push(s[j]);
else
{
if(!st.empty()&&st.top()=='(')
{
st.pop();
ans++;
}
else
{
st.push(s[j]);
}
}
}
int a=0,b=0;//a:')' b:'('
while(!st.empty())
{
char t=st.top();
if(t=='(')
b++;
else
a--;
st.pop();
}
node t;
t.a=a,t.b=b;
if(!b&&a)
{
v3.push_back(t);
}
else if(!a&&b)
{
v1.push_back(t);
}
else
{
v2.push_back(t);
}
}
ll step=0;
sort(v2.begin(),v2.end());
for(int i=0; i<v1.size(); i++)
{
step+=v1[i].b;
}
for(int i=0; i<v2.size(); i++)
{
if(step<0)
{
step=0;
}
ans+=min(step,-v2[i].a);
if(step+v2[i].a<0)
{
step=v2[i].b;
continue;
}
step+=v2[i].a+v2[i].b;
}
for(int i=0; i<v3.size(); i++)
{
if(step<0)
{
step=0;
}
ans+=min(step,-v3[i].a);
if(step+v3[i].a<0)
{
step=0;
break;//不用再继续,已经没有'('
}
step+=v3[i].a;
}
cout<<ans*2<<endl;
}
return 0;
}