c++Educational Codeforces Round 147 (Rated for Div. 2)E - Rearrange Brackets

E. Rearrange Brackets

time limit per test:2 seconds

memory limit per test:256 megabytes

input:standard input

output:standard output

A regular bracket sequence is a bracket sequence that can be transformed into a correct arithmetic expression by inserting characters "1" and "+" between the original characters of the sequence. For example:

  • bracket sequences "()()" and "(())" are regular (the resulting expressions are: "(1)+(1)" and "((1+1)+1)");
  • bracket sequences ")(", "(" and ")" are not.

You are given a regular bracket sequence. In one move, you can remove a pair of adjacent brackets such that the left one is an opening bracket and the right one is a closing bracket. Then concatenate the resulting parts without changing the order. The cost of this move is the number of brackets to the right of the right bracket of this pair.

The cost of the regular bracket sequence is the smallest total cost of the moves required to make the sequence empty.

Actually, you are not removing any brackets. Instead, you are given a regular bracket sequence and an integer k�. You can perform the following operation at most k� times:

  • extract some bracket from the sequence and insert it back at any position (between any two brackets, at the start or at the end; possibly, at the same place it was before).

After all operations are performed, the bracket sequence has to be regular. What is the smallest possible cost of the resulting regular bracket sequence?

Input

The first line contains a single integer t� (1≤t≤1041≤�≤104) — the number of testcases.

The first line of each testcase contains a single integer k� (0≤k≤50≤�≤5) — the maximum number of operations you can perform.

The second line contains a non-empty regular bracket sequence, it consists only of characters '(' and ')'.

The total length of the regular bracket sequences over all testcases doesn't exceed 2⋅1052⋅105.

Output

For each testcase, print a single integer — the smallest possible cost of the regular bracket sequence after you perform at most k� operations on it.

Example

input

7
0
()
0
(())
1
(())
5
()
1
(()()(()))
2
((())()(()())((())))
3
((())()(()())((())))

output

0
1
0
0
1
4
2

AC1:(c++)

First, let's define the cost of an RBS a bit clearer. The absolute smallest cost of removing each pair of brackets is the number of bracket pairs it's inside of. That can actually be achieved — just remove the pairs right to left (according to the positions of the opening brackets in pairs). So you can instead say that the total cost is the sum of balance values after all closing brackets. Or before all opening brackets — these are actually the same.

From that, we can code a classic dp. Imagine we are not moving brackets, but instead doing that in two separate movements: put a bracket in some buffer and place it in the string. We'd love to use dp[pos][open][close][moves]
 — the smallest answer if we processed pos
 brackets, open
 opening brackets are in the buffer, close
 closing brackets in the buffer and moves
 are performed. Sadly, that doesn't really allow moving brackets to the left, since you would have to first place the bracket, then put in it the buffer. Does that actually break anything? Apparently, no. You can make these buffer states from −k
 to k
, and think of negative values as taking a loan. These states are enough to determine the current balance of the string. Thus, enough to both update the states and check if the string stops being an RBS after placing a closing bracket.

Overall complexity: O(nk3)
.

We can do it faster, but our proof isn't that convincing.

Start by showing that there exists an optimal answer such that each move leaves the sequence an RBS. Consider a sequence of moves that ends up being an RBS. First, you can basically rearrange the moves (maybe adjusting the exact positions is required). Second, there exists a move that, performed first, leaves an RBS. Make it and propagate the proof. You can show that such a move exists by studying some cases.

Then I found it more intuitive to switch to another representation — you can look at the forest induced by the bracket sequence. The roots of the trees in it are the topmost opening and closing brackets of the RBS. Their children are the inner topmost brackets for each of them, and so on. With that representation, the answer is actually the sum of depths of all vertices.

Now for the moves. Let's move an opening bracket to the right. We won't move it after its corresponding closing bracket to not break an RBS. How will it change the tree? It will turn some children of the corresponding vertex into the children of its parent. Thus, it will decrease their depths by one, and the depths of their descendants as well. How about to the left? That will turn some children of its parent into its own children, increasing their depths (and the depths of their descendants) by one. Similar analysis can be performed for the closing brackets.

The claim is that, in the optimal answer, you should only move opening brackets and only to the right. Then they decrease the answer independently of each other. It's pretty clear that the best position to move each bracket to is as much to the right as possible — place it next to its respective closing bracket. That will decrease the answer by the size of the subtree (excluding the vertex itself).

Finally, we want to choose k
 vertices that have the largest sum of their subtrees. That can be just done greedily — pick k
 largest ones.

You don't have to build the tree explicitly for that — the size of the subtree is half of the number of brackets between an opening bracket and a corresponding closing one. So, everything can be processed with a stack.

Overall complexity: O(n)
 or O(nlogn)
.
#include <bits/stdc++.h>

using namespace std;

#define forn(i, n) for(int i = 0; i < int(n); i++)

const long long INF64 = 1e18;

long long dp[2][11][11][6];

int main(){
	int t;
	cin >> t;
	while (t--){
		int k;
		cin >> k;
		string s;
		cin >> s;
		int n = s.size();
		forn(balo, 2 * k + 1) forn(balc, 2 * k + 1) forn(mv, k + 1) dp[0][balo][balc][mv] = INF64;
		dp[0][k][k][0] = 0;
		int act = 0;
		forn(ii, n){
			int i = ii & 1;
			int ni = i ^ 1;
			forn(balo, 2 * k + 1) forn(balc, 2 * k + 1) forn(mv, k + 1)
				dp[ni][balo][balc][mv] = INF64;
			forn(mv, k + 1) forn(balo, 2 * k + 1) forn(balc, 2 * k + 1) if (dp[i][balo][balc][mv] != INF64){
				int bal = act - balo + balc;
				if (balo >= 0 && mv < k)
					dp[i][balo - 1][balc][mv + 1] = min(dp[i][balo - 1][balc][mv + 1], dp[i][balo][balc][mv] + bal);
				if (balc >= 0 && mv < k && bal > 0)
					dp[i][balo][balc - 1][mv + 1] = min(dp[i][balo][balc - 1][mv + 1], dp[i][balo][balc][mv]);
				if (s[ii] == '('){
					dp[ni][balo][balc][mv] = min(dp[ni][balo][balc][mv], dp[i][balo][balc][mv] + bal);
					if (balo + 1 <= 2 * k)
						dp[ni][balo + 1][balc][mv] = min(dp[ni][balo + 1][balc][mv], dp[i][balo][balc][mv]);
				}
				else{
					if (bal > 0)
						dp[ni][balo][balc][mv] = min(dp[ni][balo][balc][mv], dp[i][balo][balc][mv]);
					if (balc + 1 <= 2 * k)
						dp[ni][balo][balc + 1][mv] = min(dp[ni][balo][balc + 1][mv], dp[i][balo][balc][mv]);
				}
			}
			act += (s[ii] == '(' ? 1 : -1);
		}
		printf("%lld\n", *min_element(dp[n & 1][k][k], dp[n & 1][k][k] + k + 1));
	}
}

 AC2:(c++)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define deb(x) cerr<<"Line: "<<__LINE__<<", val= "<<x<<"; \n"
#define pii pair<ll,ll>
#define mp make_pair
#define fi first
#define se second
const ll N=2e5+10;
ll T,n,k,L[N],dep[N];
char c[N];
void work(){
	scanf("%lld",&k);
	scanf("%s",c+1);
	n=strlen(c+1);
	ll de=0,ans=0;
	stack<ll> s;
	vector<pii> v;
	for(ll i=1;i<=n;i++){
		if(c[i]=='('){
			de++;
			s.push(i);
		}
		else{
			de--;
			dep[i]=de;
			ans+=de;
			L[i]=s.top();
			s.pop();
			v.push_back(mp(-i+L[i]-1,i));
		}
	}
	sort(v.begin(),v.end());
	for(int i=0;i<min(ll(v.size()),k);i++){
		ans-=-v[i].fi/2-1;	
	}
	printf("%lld\n",ans);
}
signed main(){
	scanf("%lld",&T);
	while(T--){
		work();
	}
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
"educational codeforces round 103 (rated for div. 2)"是一个Codeforces平台上的教育性比赛,专为2级选手设计评级。以下是有关该比赛的回答。 "educational codeforces round 103 (rated for div. 2)"是一场Codeforces平台上的教育性比赛。Codeforces是一个为程序员提供竞赛和评级的在线平台。这场比赛是专为2级选手设计的,这意味着它适合那些在算法和数据结构方面已经积累了一定经验的选手参与。 与其他Codeforces比赛一样,这场比赛将由多个问题组成,选手需要根据给定的问题描述和测试用例,编写程序来解决这些问题。比赛的时限通常有两到三个小时,选手需要在规定的时间内提交他们的解答。他们的程序将在Codeforces的在线评测系统上运行,并根据程序的正确性和效率进行评分。 该比赛被称为"educational",意味着比赛的目的是教育性的,而不是针对专业的竞争性。这种教育性比赛为选手提供了一个学习和提高他们编程技能的机会。即使选手没有在比赛中获得很高的排名,他们也可以从其他选手的解决方案中学习,并通过参与讨论获得更多的知识。 参加"educational codeforces round 103 (rated for div. 2)"对于2级选手来说是很有意义的。他们可以通过解决难度适中的问题来测试和巩固他们的算法和编程技巧。另外,这种比赛对于提高解决问题能力,锻炼思维和提高团队合作能力也是非常有帮助的。 总的来说,"educational codeforces round 103 (rated for div. 2)"是一场为2级选手设计的教育性比赛,旨在提高他们的编程技能和算法能力。参与这样的比赛可以为选手提供学习和进步的机会,同时也促进了编程社区的交流与合作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浪子小院

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值