6716. 【2020.06.11省選模擬】T2 反諷

題目


正解

左括號記爲+1+1,右括號記爲1-1
首先答案顯然等於+2min(0,min)左括號個數-右括號個數+2|min(0,前綴min)|
隔壁大佬的方法有一部分聽得不是很懂,所以這裏就只將gmh77的方法。

考慮這樣的模型:有個二元組(a,b)(a,b),表示當前的值如果大於等於aa,那麼就會得到bb
有個經典問題:如果有若干個(a,b)(a,b),用什麼順序選取,才能使在滿足值一直大於等於00的情況下,一開始所需要的值最小。
打怪獸問題:HDU6326
這個東西可以貪心:定義(a,b)(a,b)的優劣關係:

  1. bb大於等於00的比小於00的優。
  2. bb大於等於00時,aa越小越優。
  3. bb小於00時,a+ba+b越大越優。

前面兩條都比較顯然,但第三條看起來不太好懂。
一種解釋是隔壁所云“反過來”:將操作順序以及符號反過來,原來(a,b)(a,b)可以看做先減aa再加a+ba+b,反過來就變成減a+ba+baa,記作(a+b,b)(a+b,-b)'。這時候b-b是正的,於是按照a+ba+b從小到大倒着往前做,就相當於按a+ba+b從大到小順着往後做。
或者有一種更加舒服的化學解釋方法:
bb看做熱量,當b<0b<0時,可以看做正在發生吸熱反應。
aa表示發生反應的最低能量。於是a+ba+b可以理解成活化能。
發生反應之後,活化能化爲內能。爲了支持後面的反應,轉化爲內能的活化能儘量要爲後面的反應提供能量,使其達到反應發生的最低能量。
爲了讓活化能不要浪費,按照a+ba+b從大到小的順序反應。

於是題目中的每條序列都可以視作若干個這樣的二元組。
可以發現,當一個劣的二元組在優的二元組前的時候,操作完劣的二元組之後肯定會立即執行優的二元組。於是把這些二元組合並起來,最終就會形成一個從優到劣的二元組。
兩個序列之間按照開頭的優劣順序貪心即可。
題解講得可能更清楚。
在這裏插入圖片描述


代碼

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章