左括号记为 + 1 +1 +1,右括号记为 − 1 -1 −1。
首先答案显然等于 左 括 号 个 数 − 右 括 号 个 数 + 2 ∣ m i n ( 0 , 前 缀 m i n ) ∣ 左括号个数-右括号个数+2|min(0,前缀min)| 左括号个数−右括号个数+2∣min(0,前缀min)∣
隔壁大佬的方法有一部分听得不是很懂,所以这里就只将gmh77的方法。
考虑这样的模型:有个二元组 ( a , b ) (a,b) (a,b),表示当前的值如果大于等于 a a a,那么就会得到 b b b。
有个经典问题:如果有若干个 ( a , b ) (a,b) (a,b),用什么顺序选取,才能使在满足值一直大于等于 0 0 0的情况下,一开始所需要的值最小。
打怪兽问题:HDU6326
这个东西可以贪心:定义 ( a , b ) (a,b) (a,b)的优劣关系:
前面两条都比较显然,但第三条看起来不太好懂。
一种解释是隔壁所云“反过来”:将操作顺序以及符号反过来,原来 ( a , b ) (a,b) (a,b)可以看做先减 a a a再加 a + b a+b a+b,反过来就变成减 a + b a+b a+b加 a a a,记作 ( a + b , − b ) ′ (a+b,-b)' (a+b,−b)′。这时候 − b -b −b是正的,于是按照 a + b a+b a+b从小到大倒着往前做,就相当于按 a + b a+b a+b从大到小顺着往后做。
或者有一种更加舒服的化学解释方法:
把 b b b看做热量,当 b < 0 b<0 b<0时,可以看做正在发生吸热反应。
a a a表示发生反应的最低能量。于是 a + b a+b a+b可以理解成活化能。
发生反应之后,活化能化为内能。为了支持后面的反应,转化为内能的活化能尽量要为后面的反应提供能量,使其达到反应发生的最低能量。
为了让活化能不要浪费,按照 a + b a+b a+b从大到小的顺序反应。
于是题目中的每条序列都可以视作若干个这样的二元组。
可以发现,当一个劣的二元组在优的二元组前的时候,操作完劣的二元组之后肯定会立即执行优的二元组。于是把这些二元组合并起来,最终就会形成一个从优到劣的二元组。
两个序列之间按照开头的优劣顺序贪心即可。
题解讲得可能更清楚。
using namespace std;
#include
#include
#include
#define N 1000010
int n,m;
char s[N],t[N];
struct Info{
int a,b;
} da[N],db[N];
bool cmp(Info x,Info y){
if (x.b>=0 && y.b>=0)
return x.a<y.a;
if (x.b<0 && y.b<0)
return x.a+x.b>y.a+y.b;
return x.b>y.b;
}
Info operator+(Info x,Info y){
return {-min(x.b-y.a,min(-x.a,-y.a)),x.b+y.b};
}
void calc(Info &x,Info y){
if (y.a>x.b){
x.a+=y.a-x.b;
x.b=y.a;
}
x.b+=y.b;
}
int ak,bk;
void init(char s[],int n,Info d[],int &k){
for (int i=1;i<=n;++i)
s[i]=(s[i]=='('?1:-1);
k=0;
for (int i=1;i<=n;++i){
Info nw={max(-int(s[i]),0),s[i]};
while (k && cmp(nw,d[k])){
nw=d[k]+nw;
--k;
}
d[++k]=nw;
}
}
int main(){
freopen("irony.in","r",stdin);
freopen("irony.out","w",stdout);
int T;
scanf("%d",&T);
while (T--){
scanf("%d%d%s%s",&n,&m,s+1,t+1);
init(s,n,da,ak);
init(t,m,db,bk);
int cnt=0;
for (int i=1;i<=n;++i)
cnt+=s[i];
for (int i=1;i<=m;++i)
cnt+=t[i];
int i=1,j=1;
Info ans={0,0};
while (i<=ak && j<=bk)
if (cmp(da[i],db[j]))
calc(ans,da[i++]);
else
calc(ans,db[j++]);
for (;i<=ak;++i)
calc(ans,da[i]);
for (;j<=bk;++j)
calc(ans,db[j]);
printf("%d\n",cnt+2*ans.a);
}
return 0;
}