题意:
解法:
将左括号看作1,右括号看作-1,那么合法的括号序列一定前缀和>=0且最后总和=0.
我们对每个串计算前缀和,统计前缀和过程中的最小值mi[i]和总和sum[i].
1.如果0<=mi[i]<=sum[i],那么一定放在左边,优先选择.
2.如果mi[i]<0但sum[i]>0,那么对这样的二元组(mi,sum)按照mi从大到小排序,优先选择mi大的.
3.如果mi[i]<=sum[i]<0,考虑放置的先后顺序:
设有(mi[i],sum[i]),(mi[j],sum[j]),考虑什么时候i放在j的左边:
假设i放在左边,那么sum[i]+mi[j]>sum[j]+mi[i],移项得sum[i]-mi[i]>sum[j]-mi[j],
因此按照sum-mi从大到小排序即可.
为什么第3点的式子是sum[i]+mi[j]>sum[j]+mi[i]呢?
因为i串的后面加上j串时,需要满足S+sum[i]+mi[j]>=0,因此sum[i]+mi[j]越大越好.
code:
#include<bits/stdc++.h>
#define int long long
#define PI pair<int,int>
using namespace std;
const int maxm=2e6+5;
vector<PI>f,g;
int mark[maxm];
int sum[maxm];
int mi[maxm];
int n;
void solve(){
cin>>n;
for(int i=1;i<=n;i++){
string s;cin>>s;
mi[i]=1e9;
for(auto j:s){
if(j=='(')sum[i]++;
else sum[i]--;
mi[i]=min(mi[i],sum[i]);
}
}
int S=0;
for(int i=1;i<=n;i++){
if(mi[i]>=0){
mark[i]=1;
S+=sum[i];
}else if(sum[i]>=0){
f.push_back({mi[i],sum[i]});
}else{
g.push_back({mi[i],sum[i]});
}
}
sort(f.begin(),f.end(),[](PI a,PI b){
return a.first>b.first;
});
for(auto i:f){
if(S+i.first<0){
cout<<"No"<<endl;
return ;
}
S+=i.second;
}
sort(g.begin(),g.end(),[](PI a,PI b){
return a.second-a.first>b.second-b.first;
});
for(auto i:g){
if(S+i.first<0){
cout<<"No"<<endl;
return ;
}
S+=i.second;
}
if(S!=0)cout<<"No"<<endl;
else cout<<"Yes"<<endl;
}
signed main(){
ios::sync_with_stdio(0);
solve();
return 0;
}