「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 ...
随机推荐
- hzwer与逆序对
codevs——4163 hzwer与逆序对 貌似这个题和上个题是一样的((⊙o⊙)…) 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 黄金 Gold 题解 题目 ...
- 常用业务返回对象类ResponseJson
目录 1.ResponseJson类 2.使用举例 1.ResponseJson类 import java.io.Serializable; public class ResponseJson imp ...
- 配置maven从私服上下载构件
maven 本地setting.xml配置 <!--配置maven从私服上下载构件 --> <profiles> <profile> <repositorie ...
- SolidEdge 如何由装配图快速进行标注和零件序号编写 制作BOM表
点击"零件明细表",然后点击要生成序号的视图,然后点击前面两项(自动标号和放置清单),点击完成后效果如下图所示. 在点击完成之前,先点击他前面的一个按钮,取消勾选"项 ...
- hdu 1250 Hat's Fibonacci
pid=1250">点击此处就可以传送hdu 1250 Problem Description A Fibonacci sequence is calculated by adding ...
- C++学习总结 复习篇2
延续上一小节内容:下面继续讲解虚函数和多态 虚函数和多态 基类指针可以指向任何派生类的对象,但是不能调用派生类对象的成员. 但是,基类可以调用覆盖了虚函数的函数.(现在调用将来,这有问题,说明现在 ...
- Java经常使用类及其经常用法
1.ArrayList java.util.ArrayList<E> add(E e) //插入尾部 add(int index, E element) remove(int index) ...
- 【前端JS】radio 可单选可点击取消选中
普通情况下 radio 单选框仅仅能实现多选一的效果,可是一旦选择当中一个后,这个单选框就不可点击取消其选中状态了.这样的功能在某些业务环境下并不适用.有时我们既须要单选框的多选一效果.也须要复选框的 ...
- 为activity添加左右手势识别
android开发中为activity添加左右手势识别.如右滑关闭当前页面 /* * for左右手势 * 1.复制以下的内容到目标Activity * 2.目标Activity的onCreate()调 ...
- 信雅达面试题atoi函数实现
atoi函数: 功 能: 把字符串转换成整型数. 名字来源:ASCII to integer 的缩写. 原型: int atoi(const char *nptr); 函数说明 参数nptr字符串,如 ...