「HNSDFZ暑期集训 测试1」「LuoguT36485」 括号(贪心
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」 括号(贪心的更多相关文章
- 「HNSDFZ暑期集训 测试1」「LuoguT36488」 连连看
题目描述 给定一个n × m的矩形地图,每个各自上可能为空,可能有牌,牌上有一个数字. 对于两张同样数字的牌,如果我们可以在地图上用不超过三根水平或竖直,在地图界内,且不经过其他牌的线段将两张牌连起来 ...
- loj #6046. 「雅礼集训 2017 Day8」爷
#6046. 「雅礼集训 2017 Day8」爷 题目描述 如果你对山口丁和 G&P 没有兴趣,可以无视题目背景,因为你估计看不懂 …… 在第 63 回战车道全国高中生大赛中,军神西住美穗带领 ...
- LOJ_6045_「雅礼集训 2017 Day8」价 _最小割
LOJ_6045_「雅礼集训 2017 Day8」价 _最小割 描述: 有$n$种减肥药,$n$种药材,每种减肥药有一些对应的药材和一个收益. 假设选择吃下$K$种减肥药,那么需要这$K$种减肥药包含 ...
- 「雅礼集训 2017 Day7」事情的相似度
「雅礼集训 2017 Day7」事情的相似度 题目链接 我们先将字符串建后缀自动机.然后对于两个前缀\([1,i]\),\([1,j]\),他们的最长公共后缀长度就是他们在\(fail\)树上对应节点 ...
- 「雅礼集训 2017 Day2」解题报告
「雅礼集训 2017 Day2」水箱 我怎么知道这种题目都能构造树形结构. 根据高度构造一棵树,在树上倍增找到最大的小于约束条件高度的隔板,开一个 \(vector\) 记录一下,然后对于每个 \(v ...
- 「雅礼集训 2017 Day1」 解题报告
「雅礼集训 2017 Day1」市场 挺神仙的一题.涉及区间加.区间除.区间最小值和区间和.虽然标算就是暴力,但是复杂度是有保证的. 我们知道如果线段树上的一个结点,\(max=min\) 或者 \( ...
- [LOJ 6031]「雅礼集训 2017 Day1」字符串
[LOJ 6031] 「雅礼集训 2017 Day1」字符串 题意 给定一个长度为 \(n\) 的字符串 \(s\), \(m\) 对 \((l_i,r_i)\), 回答 \(q\) 个询问. 每个询 ...
- [LOJ 6030]「雅礼集训 2017 Day1」矩阵
[LOJ 6030] 「雅礼集训 2017 Day1」矩阵 题意 给定一个 \(n\times n\) 的 01 矩阵, 每次操作可以将一行转置后赋值给某一列, 问最少几次操作能让矩阵全为 1. 无解 ...
- [LOJ 6029]「雅礼集训 2017 Day1」市场
[LOJ 6029] 「雅礼集训 2017 Day1」市场 题意 给定一个长度为 \(n\) 的数列(从 \(0\) 开始标号), 要求执行 \(q\) 次操作, 每次操作为如下四种操作之一: 1 l ...
随机推荐
- Vijos——1359 Superprime
Superprime 描述 农民约翰的母牛总是生产出最好的肋骨.你能通过农民约翰和美国农业部标记在每根肋骨上的数字认出它们. 农民约翰确定他卖给买方的是真正的质数肋骨,是因为从右边开始切下肋骨,每次还 ...
- 《Java虚拟机原理图解》1.5、 class文件中的方法表集合--method方法在class文件中是怎样组织的
0. 前言 了解JVM虚拟机原理是每一个Java程序员修炼的必经之路.但是由于JVM虚拟机中有很多的东西讲述的比较宽泛,在当前接触到的关于JVM虚拟机原理的教程或者博客中,绝大部分都是充斥的文字性的描 ...
- 干货--安装eclipse-hadoop-plugin插件及HDFS API编程两个遇到的重要错误的解决
在Windows的eclipse上写hdfs的API程序,都会遇到两个错误,在网上查了很多资料,都没有解决的办法,经过了很多时间的研究,终于把这个问题解决了 错误是 1.java.io.IOExcep ...
- iOS之中国银联移动支付控件升级的问题
自从11月以来,如果用户安装了集成了中国银联手机支付SDK的app,那么在使用银联支付的时候,会发现,不能调用银联支付方式,并且弹出一个提示”银联手机支付已升级请更新客户端8100010”.如下图: ...
- SolidEdge如何快速绘制并完全定义槽型孔
如果你点击A之后形成的圆弧不是你想要的 你试着换个方向,如下图所示 有时候只有一个方形可以形成你要的半圆
- iphone 消息推送 实现
IPhone 消息推送实现 参考 资料 http://blog.csdn.net/victormokai/article/details/39501277 对生成pem 的补充 拿到mac 上生成导出 ...
- 当电视沦为“情怀”,5G能不能拯救它?(zz)
文|佘凯文 来源|智能相对论(aixdlun) 现阶段,智能家居行业极度期待5G的到来,甚至超过手机.行业对于颠覆性的升级的欲望极其强烈,纵观整个智能家居行业,除了像智能音箱外的偶尔单品能够“引爆”市 ...
- openwrt network 初始化
openwrt 烧写完成之后, 第一次启动会设置 network 的相关参数, 如 ip地址, mac地址, 等. 这里跟踪一下启动之后直到网络参数设置的过程. /sbin/init -> pr ...
- (转)使用MAT比较多个heap dump文件
使用MAT比较多个heap dump文件 调试内存泄露时,有时候适时比较2个或多个heap dump文件是很有用的.这时需要生成多个单独的HPROF文件. 下面是一些关于如何在MAT里比较多个heap ...
- 我遇到的错误curl: (7) Failed to connect to 127.0.0.1 port 1086: Connection refused
今天我用curl命令,无论如何都是出现: curl: (7) Failed to connect to 127.0.0.1 port 1086: Connection refused 找了很久,不知道 ...