Description


给定一个由左括号'('和右括号')'组成的字符串s,其中第i个括号的权值为ai。

我们定义一个括号序列t为合法括号序列,当且仅当满足下列条件之一:

1.t为空串

2.t=(A),其中A为一个合法括号序列

3.t=AB,其中A,B均为合法括号序列

比如(()()),()(())均为合法括号序列,但((), ())(不是合法括号序列。

Input


输入第一行一个整数n,表示s的长度。

第二行一个长度为n,且由括号组成的字符串s。

第三行n个整数,第i个整数ai表示第i个括号的值。

Output


输出仅一行一个整数,表示答案。

Sample Input1


6
())(()
1 2 1 2 1 2

Sample Output1


7

Sample Input2


6
((()))
2 1 -2 1 2 3

Sample Output2


8

Hint


40%的数据n<=20,0<=ai<=100

接下来30%的数据 n<=2000,|ai|<=1e5

接下来30%的数据 n<=2e5,|ai|<=1e3,左括号全都在右括号的左边

题解


官方题解:

分情况讨论
n<=2000时 用dp,F [ i ] [ j ]表示前i个中有j个左括号时的最大值
n >2000时,分别对左括号的值和右括号的值排序(cmp从大到小),用for循环从1走一遍,若a[i]+b[i]>0 ans+=a[i]+b[i],否则return.

但是我的思路可以把n取到1e6并且不需要特殊性质啊!QAQ

我们先假设现在已经从头开始扫了一段括号序列,并且前一段已经标记了最优的序列有哪些括号。对于现在新加进来的括号,我们仍然要试图维持当前选择最优。

如果是左括号,我们不做任何处理(也做不了什么);

如果是右括号,那么不外乎三种情况:

1.不做任何处理;

2.在这个右括号之前找一个未被选的左括号,与其配对(标记此左括号和右括号);

3.在这个右括号之前找一个被选了的右括号,将其替代(清除前面的右括号的标记,并且标记新的右括号)

只要在这三种操作中取一个最优操作,就仍然可以保持当前最优。

那么,用一个for从头至尾循环,复杂度O(n),

对每个当前括号,做以上判断,

其中的往前找要求的括号的操作(2)和操作(3)可以用堆实现,复杂度O(logn)

一共O(nlogn)

代码://考场代码 因为可以水到分所以懒得写堆了(其实可以直接调用priority_queue 也很方便)

 #include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int s[];
int q[];
bool sf[];
int a[];
int b[];
bool cmp(int qaq,int qwq)
{
return qaq>qwq;
}
int main()
{
int n;
cin>>n;
if(n<)
{
for(int i=;i<=n;++i)
{
char x;
cin>>x;
if(x=='(')s[i]=;
else s[i]=;
}
for(int i=;i<=n;++i)
{
cin>>q[i];
//cout<<i<<" "<<s[i]<<" "<<a[i]<<endl;
if(s[i]==)
{
int u=-,pu=;
for(int j=i-;j;--j)
if(s[j]==&&!sf[j])
{
if(q[j]>u){u=q[j];pu=j;}
}
int v=,pv=;
for(int j=i-;j;--j)
if(s[j]==&&sf[j])
{
if(q[j]<v){v=q[j];pv=j;}
}
//cout<<u<<" "<<pu<<" "<<v<<" "<<pv;
if(pu&&pv)
{
if(u+q[i]>=q[i]-v&&u+q[i]>)
{
sf[pu]=;sf[i]=;
}
else if(q[i]-v>u+q[i]&&q[i]-v>)
{
sf[pv]=;sf[i]=;
}
}
else
{
if(pu&&u+q[i]>)
{
sf[pu]=;sf[i]=;
}
else if(pv&&q[i]-v>)
{
sf[pv]=;sf[i]=;
}
}
//cout<<endl;
}
}
int ans=;
for(int i=;i<=n;++i)
if(sf[i]){ans+=q[i];}
cout<<ans;//强大怪!!!
return ;
}
else
{
for(int i=;i<=n;++i)
{
char x;
cin>>x;
if(x=='(')s[i]=;
else s[i]=;
}
int toa=,tob=;
for(int i=;i<=n;++i)
{
int x;
scanf("%d",&x);
if(s[i]==)a[++toa]=x;
else b[++tob]=x;
}
sort(a+,a+toa+,cmp);
sort(b+,b+tob+,cmp);
int ans=;
for(int i=;i<=min(toa,tob);++i)
{
if(a[i]+b[i]>)ans+=(a[i]+b[i]);
else {cout<<ans;return ;}
}
cout<<ans;//强大怪!!!
return ;
}
}
//注释强大怪 你会rp++

UPD

$O(nlogn)$的堆写法↓

 /*
qwerta
T36485 括号 Accepted
100
代码 C++,0.7KB
提交时间 2018-11-05 20:42:18
耗时/内存 442ms, 2124KB
*/
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
char ch[];
int v[];
priority_queue<int,vector<int>,greater<int> >r;//r放右括号
priority_queue<int>l;//l放左括号
int main()
{
//freopen("a.in","r",stdin);
ios::sync_with_stdio(false);
int n;
cin>>n;
for(int i=;i<=n;++i)
cin>>ch[i];
for(int i=;i<=n;++i)
cin>>v[i];
//
int ans=;
for(int i=;i<=n;++i)
{
if(ch[i]=='(')
{
l.push(v[i]);
}
else
{
int x,y;
if(l.empty())x=-;//赋成-1不碍事儿
else x=v[i]+l.top();
if(r.empty())y=-;
else y=v[i]-r.top();
if(x>=y&&x>=)//找个没用过的左括号
{
ans+=x;
l.pop();
r.push(v[i]);
}
else if(y>=x&&y>=)//替代一个用过的右括号
{
ans+=y;
r.pop();
r.push(v[i]);
}
}
}
cout<<ans;
return ;
}

「HNSDFZ暑期集训 测试1」「LuoguT36485」 括号(贪心的更多相关文章

  1. 「HNSDFZ暑期集训 测试1」「LuoguT36488」 连连看

    题目描述 给定一个n × m的矩形地图,每个各自上可能为空,可能有牌,牌上有一个数字. 对于两张同样数字的牌,如果我们可以在地图上用不超过三根水平或竖直,在地图界内,且不经过其他牌的线段将两张牌连起来 ...

  2. loj #6046. 「雅礼集训 2017 Day8」爷

    #6046. 「雅礼集训 2017 Day8」爷 题目描述 如果你对山口丁和 G&P 没有兴趣,可以无视题目背景,因为你估计看不懂 …… 在第 63 回战车道全国高中生大赛中,军神西住美穗带领 ...

  3. LOJ_6045_「雅礼集训 2017 Day8」价 _最小割

    LOJ_6045_「雅礼集训 2017 Day8」价 _最小割 描述: 有$n$种减肥药,$n$种药材,每种减肥药有一些对应的药材和一个收益. 假设选择吃下$K$种减肥药,那么需要这$K$种减肥药包含 ...

  4. 「雅礼集训 2017 Day7」事情的相似度

    「雅礼集训 2017 Day7」事情的相似度 题目链接 我们先将字符串建后缀自动机.然后对于两个前缀\([1,i]\),\([1,j]\),他们的最长公共后缀长度就是他们在\(fail\)树上对应节点 ...

  5. 「雅礼集训 2017 Day2」解题报告

    「雅礼集训 2017 Day2」水箱 我怎么知道这种题目都能构造树形结构. 根据高度构造一棵树,在树上倍增找到最大的小于约束条件高度的隔板,开一个 \(vector\) 记录一下,然后对于每个 \(v ...

  6. 「雅礼集训 2017 Day1」 解题报告

    「雅礼集训 2017 Day1」市场 挺神仙的一题.涉及区间加.区间除.区间最小值和区间和.虽然标算就是暴力,但是复杂度是有保证的. 我们知道如果线段树上的一个结点,\(max=min\) 或者 \( ...

  7. [LOJ 6031]「雅礼集训 2017 Day1」字符串

    [LOJ 6031] 「雅礼集训 2017 Day1」字符串 题意 给定一个长度为 \(n\) 的字符串 \(s\), \(m\) 对 \((l_i,r_i)\), 回答 \(q\) 个询问. 每个询 ...

  8. [LOJ 6030]「雅礼集训 2017 Day1」矩阵

    [LOJ 6030] 「雅礼集训 2017 Day1」矩阵 题意 给定一个 \(n\times n\) 的 01 矩阵, 每次操作可以将一行转置后赋值给某一列, 问最少几次操作能让矩阵全为 1. 无解 ...

  9. [LOJ 6029]「雅礼集训 2017 Day1」市场

    [LOJ 6029] 「雅礼集训 2017 Day1」市场 题意 给定一个长度为 \(n\) 的数列(从 \(0\) 开始标号), 要求执行 \(q\) 次操作, 每次操作为如下四种操作之一: 1 l ...

随机推荐

  1. hzwer与逆序对

    codevs——4163 hzwer与逆序对 貌似这个题和上个题是一样的((⊙o⊙)…)  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 黄金 Gold 题解       题目 ...

  2. 常用业务返回对象类ResponseJson

    目录 1.ResponseJson类 2.使用举例 1.ResponseJson类 import java.io.Serializable; public class ResponseJson imp ...

  3. 配置maven从私服上下载构件

    maven 本地setting.xml配置 <!--配置maven从私服上下载构件 --> <profiles> <profile> <repositorie ...

  4. SolidEdge 如何由装配图快速进行标注和零件序号编写 制作BOM表

    点击"零件明细表",然后点击要生成序号的视图,然后点击前面两项(自动标号和放置清单),点击完成后效果如下图所示.   在点击完成之前,先点击他前面的一个按钮,取消勾选"项 ...

  5. hdu 1250 Hat&#39;s Fibonacci

    pid=1250">点击此处就可以传送hdu 1250 Problem Description A Fibonacci sequence is calculated by adding ...

  6. C++学习总结 复习篇2

      延续上一小节内容:下面继续讲解虚函数和多态 虚函数和多态 基类指针可以指向任何派生类的对象,但是不能调用派生类对象的成员. 但是,基类可以调用覆盖了虚函数的函数.(现在调用将来,这有问题,说明现在 ...

  7. Java经常使用类及其经常用法

    1.ArrayList java.util.ArrayList<E> add(E e) //插入尾部 add(int index, E element) remove(int index) ...

  8. 【前端JS】radio 可单选可点击取消选中

    普通情况下 radio 单选框仅仅能实现多选一的效果,可是一旦选择当中一个后,这个单选框就不可点击取消其选中状态了.这样的功能在某些业务环境下并不适用.有时我们既须要单选框的多选一效果.也须要复选框的 ...

  9. 为activity添加左右手势识别

    android开发中为activity添加左右手势识别.如右滑关闭当前页面 /* * for左右手势 * 1.复制以下的内容到目标Activity * 2.目标Activity的onCreate()调 ...

  10. 信雅达面试题atoi函数实现

    atoi函数: 功 能: 把字符串转换成整型数. 名字来源:ASCII to integer 的缩写. 原型: int atoi(const char *nptr); 函数说明 参数nptr字符串,如 ...