[CSP-S模拟测试]:括号密码(贪心)

题目描述

在“无限神机”的核心上,有一个奇怪的括号密码,密码初始已经有一个括号序列,有$n$个限制条件,每个限制条件描述为$l_i$和$r_i$,表示区间$[l_i,r_i]$的括号序列必须合法。调整密码只有一种方式:交换括号序列的任意两个字符。求使得密码满足所有条件最少的交换次数。
括号序列合法定义为:
  $1.$空串$""$是一个合法的括号序列
  $2.$如果$"X"$和$"Y"$是合法的括号序列,则$"XY"$(连接$X$和$Y$)是合法的括号序列
  $3.$如果$"X"$是合法的括号序列,则$"(X)"$是合法的括号序列
  $4.$每个合法的括号序列均可由上述规则推导出。
  例如,$"","()","()()()","(()())"$和$"(((())))"$都是合法的括号序列。显然,只有长度为偶数的才有可能是合法的括号序列


输入格式

第一行有一个字符串$s$,表示原括号序列
第二行一个整数$n$,表示限制条件的个数
第三行$n$个整数,表示$l_i$
第四行$n$个整数,表示$r_i$


输出格式

输出一个整数,表示最少交换次数,无解输出$-1$


样例

样例输入1:

)(
4
0 0 0 0
1 1 1 1

样例输出1:

1

样例输入2:

(((())
2
0 2
1 3

样例输出2:

2


数据范围与提示

样例$1$解释:

$L$和$R$描述了$4$个相同的条件,即要求从$s[0]$到$s[1]$是正确的括号序列。只需要做$1$次交换$s[0]$和$s[1]$就可以得到正确的括号序列。

样例$2$解释:

需要交换$(s[1],s[4])$和交换$(s[3],s[5])$

数据范围:

每个测试点的数据规模及特点如下表所示。设字符串长度为$|S|$


题解

先来考虑区间不重叠的情况:

对每个区间,统计区间前缀和,设前缀和最小值为$w$,区间总和为$a$($a$必须为偶数,否则无解) 使$a$变为$0$,需要从区间外引进括号,只计算引进’)‘数量,最后判断如果所有条件区间的’)‘不够,再从外面进口’)’ 若$a>0$,则需引进$\frac{a}{2}$个’)’,使得$a$变为$0$,每次贪心选择最右边的’(‘修改,$w$不改变(将这些进口操作记录到答案) 若$a<0$,需将这里的’)’出口到其它区间,贪心选择最左边的’)’修改,$w$会增加$|a|$(但这些修改不计算入答案,我们只计算引入’(‘数量) 最后加上$\frac{w}{2}$次区间内部操作,使得前缀和不存在负数。

再来考虑会出现重叠,但是无嵌套:

不妨设这两个区间分别为$l_i\sim r_i$和$l_j\sim r_j$,且$l_j<r_i$。

有一个很简单的解决方法,可以直接将这两个区间拆成$l_i\sim l_j-1,l_j\sim r_i,r_i+1\sim r_j$即可。

如果区间有嵌套仍可以按这种方法解决,代码实现细节比较多。

时间复杂度:$\Theta(n)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
struct rec{int l,r;}e[100001];
int n;
int cnt=1,suml,sumr,resl,resr;
char ch[100001];
int l[100001],r[100001];
vector<int> vec[100001];
vector<char> s[100001];
map<vector<int>,int>mp;
int ans;
void work(int x)
{
	ans+=(min(l[x],r[x])+1)>>1;
	int mid=(l[x]-r[x])>>1;
	if(mid<0)
	{
		mid=-mid;
		int flag=min(mid,resl);
		mid-=flag;
		resl-=flag;
		ans+=flag;
		resr+=mid;
	}
	else
	{
		int flag=min(mid,resr);
		mid-=flag;
		resr-=flag;
		ans+=flag;
		resl+=mid;
	}
}
int main()
{
	scanf("%s%d",ch+1,&n);
	int len=strlen(ch+1);
	for(int i=1;i<=n;i++){scanf("%d",&e[i].l);e[i].l++;}
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&e[i].r);
		e[i].r++;
		for(int j=e[i].l;j<=e[i].r;j++)vec[j].push_back(i);
	}
	mp[vec[0]]=1;
	for(int i=1;i<=len;i++)
	{
		if(!mp[vec[i]])mp[vec[i]]=++cnt;
		s[mp[vec[i]]].push_back(ch[i]);
	}
	for(int i=0;i<s[1].size();i++)
		if(s[1][i]=='(')suml++;
		else sumr++;
	for(int i=2,L,R;i<=cnt;i++)
	{
		L=R=0;
		for(int j=0;j<s[i].size();j++)
		{
			if(s[i][j]=='(')L++;
			else R++;
			l[i]=max(l[i],R-L);
		}
		L=R=0;
		for(int j=s[i].size()-1;j>=0;j--)
		{
			if(s[i][j]=='(')L++;
			else R++;
			r[i]=max(r[i],L-R);
		}
		if(abs(L-R)&1){puts("-1");return 0;}
	}
	for(int i=2;i<=cnt;i++)work(i);
	int flag=min(resl,resr);
	ans+=flag;
	resl-=flag;
	resr-=flag;
	if(suml<resl||sumr<resr){puts("-1");return 0;}
	ans+=resl+resr;
	printf("%d",ans);
	return 0;
}

rp++

posted @ 2019-10-26 06:56  HEOI-动动  阅读(367)  评论(0编辑  收藏  举报