cf1598f RBS
定义括号序列为只包括 \(\texttt{(}\) 和 \(\texttt{)}\) 的字符串。一个匹配的括号序列 (简记为 RBS) 满足,可以在其中加入 \(1\) 和 \(+\),将其转化为合法的代数式,例如:
- \(\texttt{()()}\) 和 \(\texttt{(())}\) 是匹配的
- \(\texttt{)(}\) 和 \(\texttt{(}\) 和 \(\texttt{)}\) 不是
将两个字符串拼接在一起简记为 \(x+y\) 。例如,\(\texttt{()()}+\texttt{)(}=\texttt{()())(}\) .
给定 \(n\) 个括号序列 \(s_1\sim s_n\) ,你可以将他们任意重新排序,要求使得最终排序后的字符串满足 \(s_1+\dots+s_n\) 的 RBS 前缀个数最多。
\(1\leq n\leq 20,\sum |s_i|\leq 4\cdot 10^5\)
\(20=\) 状压 .
\(dp(S)\) 表示已经选择集合为 \(S\) 的字符串的最大代价.
首先,如果 \(S\) 中的字符串排列出现 \(<0\) 的位置肯定不合法. 但是,观察得到,对于状态 \(S\) ,\(\texttt{(}\) 的个数 \(-\) \(\texttt{)}\) 的个数的值是一定的,所以,对于新加入字符串能产生贡献的位置也是固定的. 考虑加入 \(s_i\) ,设加入 \(s_i\) 的贡献是 \(w\) ,那么出现两种情况,加入 \(s_i\) 之后使得整个字符串出现 \(<0\) 的位置,那么,\(dp(S)+w\) 与答案取最大值即可;否则,用 \(dp(S)+w\) 去跟新 \(dp(s+i)\) .
现在剩下的问题就是如果求出对于 \(s_i\) 中每种位置的贡献,产生贡献的位置必定是前缀最小值,并且一定是非正数,所以考虑先处理出这些位置,发现单调不增,那么相同的一段的数量就是当前此种位置的贡献了.
(本来是看到 ds 的 tag 才去做的,ds 呢,用到 ds 了吗?)
时间复杂度 : \(O(\sum|s_i|+2^n)\)
空间复杂度 : \(O(2^n+\sum |s_i|)\)
code
#include<bits/stdc++.h>
using namespace std;
const int N=20,L=4e5+10;
int n;
string str[N];
int w[N][L],mn[N];
int a[N],sum[1<<N];
int dp[1<<N];
int ans=0;
void work(string s,int id){
vector<int>v;
int tmp=0;
for(int i=0;i<(int)s.size();i++){
tmp+=s[i]==')'?-1:1;
mn[id]=min(mn[id],tmp);
if(s[i]==')'&&tmp<=0&&tmp==mn[id])v.push_back(-tmp);
}
a[id]=tmp;
for(int i=0;i<(int)v.size();i++){
int cnt=0,j=i;
for(j=i;j<(int)v.size();j++){
if(v[i]==v[j])++cnt;
else break;
}
w[id][v[i]]=cnt;
i=j-1;
}
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=0;i<n;i++)cin>>str[i];
memset(mn,0x3f3f3f3f,sizeof(mn));
for(int i=0;i<n;i++)work(str[i],i);
for(int mask=0;mask<(1<<n);mask++){
for(int i=0;i<n;i++)if(mask&(1<<i))sum[mask]+=a[i];
}
memset(dp,-0x3f3f3f,sizeof(dp));
for(int i=0;i<n;i++){
if(mn[i]<0)ans=max(ans,w[i][0]);
else{
dp[1<<i]=w[i][0];
ans=max(ans,dp[1<<i]);
}
}
for(int mask=1;mask<(1<<n);mask++){
if(dp[mask]<0)continue;
for(int i=0;i<n;i++){
if((mask&(1<<i))||sum[mask]<0)continue;
if(sum[mask]+mn[i]<0)ans=max(ans,dp[mask]+w[i][sum[mask]]);
else{
dp[mask|(1<<i)]=max(dp[mask|(1<<i)],dp[mask]+w[i][sum[mask]]);
ans=max(ans,dp[mask|(1<<i)]);
}
}
}
cout<<ans<<endl;
return 0;
}
/*inline? ll or int? size? min max?*/

浙公网安备 33010602011771号