Messy(贪心+思维)

Problem - 1262C - Codeforces

你厌倦了你那乱糟糟的房间,所以你决定把它打扫干净。

你的房间是一个长度为n的括号序列s=s1s2...sn。这个字符串的每个字符都是一个开括号'('或一个闭括号')'。

在一次操作中,你可以选择s的任何一个连续的子串并将其倒置。换句话说,你可以选择任何子串s[l...r]=sl,sl+1,...,sr并将其中的元素顺序改为sr,sr-1,...,sl。

例如,如果你决定将字符串s="(()) "的子串s[2...4]反转,它就等于s="()()"。

正则(又称平衡)括号序列是指通过在序列的原始字符之间插入字符'1'和'+',可以转化为正确的算术表达式的括号序列。例如,括号序列"()()"、"()) "是有规律的(产生的表达式是。"(1)+(1)", "((1+1)+1)"),而")("和"("则不是。

一个字符串s的前缀是一个从位置1开始的子串。例如,对于s="(())()",有6个前缀。"(", "(", "()", "())", "())("和"()()"。

在你看来,一个整齐干净的房间s是一个括号序列,即。

整个字符串s是一个有规律的括号序列。
而且这个序列正好有k个前缀是有规律的(包括整个s本身)。
例如,如果k=2,那么"()() "就是一个整齐干净的房间。

你希望最多使用n个操作来使你的房间整洁干净。操作是一个接一个按顺序应用的。

可以保证答案的存在。请注意,你不需要最小化操作的数量:找到任何方法,在n个或更少的操作中实现所需的配置。

输入
第一行包含整数t(1≤t≤100)--输入的测试用例的数量。接着是t个测试用例。

测试用例的第一行包含两个整数n和k(1≤k≤n2,2≤n≤2000,n为偶数)--s的长度和所需的正则前缀数。

测试用例的第二行包含长度为n的s--给出的括号序列。它只包含'('和')'。

可以保证在给定的字符串中正好有n2个字符'('和正好n2个字符')'。

在输入的所有测试案例中,所有数值n的总和不超过2000。

输出
对每个测试案例打印一个答案。

在第一行打印整数m(0≤m≤n)--操作的数量。你不需要使m最小化,任何数值都是合适的。

在接下来的m行中打印操作的描述,每行应包含两个整数l,r(1≤l≤r≤n),代表s[l...r]=slsl+1...sr的单一反向操作。操作是一个接一个按顺序应用的。

所有运算后的最终s应该是有规律的,同时它应该正好是k个有规律的前缀(包括s)。

保证答案的存在。如果有几个可能的答案,你可以打印任何一个。

例子
InputCopy
4
8 2
()(())()
10 3
))()()()((
2 1
()
2 1
)(
输出拷贝
4
3 4
1 1
5 8
2 2
3
4 10
1 4
6 7
0
1
1 2
注意
在第一个例子中,最后的序列是"()()())",其中两个前缀是有规律的,"() "和"()()"。请注意,除了 "5 8 "以外的所有操作在例子的输出中都是无用的(它们不改变s)。

一个关于括号序列的规律,如果一个括号序列为偶数项.且(与)的个数相同,可以通过进行将区间[l,r]里的内容翻转,使其变为()()()...((...))这样的形式.

所以根据题意先构造出一个为k个(),后全为((..))的形式即可,接下来暴力反转即可

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int n,k;
string s;
pair<int,int> ans[2005];
void rever(int l,int r)
{
	for(int i = 0; i < (r - l +1)/2 ;i++)
	{
		swap(s[l + i],s[r - i]);
	}
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int t;
	cin >> t;
	while(t--)
	{
		int cnt = 0;
		cin >> n >> k;
		
		cin >> s;
		string res;
		for(int i = 1; i < k; i++)
		{
			res += "()";
		} 
		for(int i = 1; i <=(n - k*2)/2 + 1; i++)
		res += "(";
		for(int i = 1; i<=(n - k*2)/2 + 1; i++)
		res +=")";
		for(int i = 0;i < n ;i++)
		{
			int j = i;
			while(s[j] != res[i])
			{
				j ++;
			}
			ans[++cnt].first = i + 1;
			ans[cnt].second = j + 1;
			rever(i,j);
		}
		cout << cnt <<endl;
		for(int i = 1; i <= cnt;i ++)
		{
			cout <<ans[i].first <<" "<< ans[i].second <<endl;
		}
		
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值