@bzoj - 4922@ [Lydsy1706月赛]Karp-de-Chant Number
@description@
卡常数被称为计算机算法竞赛之中最神奇的一类数字,主要特点集中于令人捉摸不透,有时候会让水平很高的选手迷之超时。
普遍认为卡常数是埃及人Qa'a及后人发现的常数。也可认为是卡普雷卡尔(Kaprekar)常数的别称。主要用于求解括号序列问题。
据考证,卡(Qa'a)是古埃及第一王朝的最后一位法老。他发现并研究了一种常数,后世以他的名字叫做卡常数。卡特兰数的起源也是因为卡的后人与特兰克斯结婚,生下来的孩子就叫卡特兰,而他只是发表了祖传的家书而已。Sereja也是卡的后人,提出括号序列问题,也是从家书里得到的资料。然而Sereja为了不让这个秘密公开,于是隐瞒了这道题的真正做法。可是由于卡的后人不是各个都像卡特兰一样爱慕虚荣,这一算法也无法找到。“欲见贤人而不以其道,犹欲其入而闭之门也”。卡之常数的奥秘,需要以一颗诚心去追寻。
【以上全是瞎 BB,不过还蛮有意思的 www】
现给定n个括号序列,你需要选择若干序列,将它们按一定的顺序从左往右拼接起来,得到一个合法的括号序列。
显然,这个问题可以用卡常数解决,为了检验你是否会卡常数,请写一个程序,计算可以得到的合法的括号序列的长度的最大值。
input:
第一行包含一个正整数n(1<=n<=300),表示括号序列的个数。
接下来n行,每行一个长度在[1,300]之间的括号序列,仅由小括号构成。
output:
输出一行一个整数,即最大长度,注意你可以一个序列也不选,此时长度为0。
sample input:
3
())
((()
)()
sample output:
10
**sample explain **:
按{2,1,3}的顺序拼接得到((()()))(),总长度为10。
@solution@
首先有个小性质:假如在不拼接的情况,一个括号已经有了匹配,那么拼接后这个括号的匹配不会变化。可以根据我们做括号匹配的过程理解这个性质。
所以基于此,我们可以把串中能匹配的括号先匹配完,剩下的部分一定是形如 “)))))....))(((....(((” 的样子。
我们将这部分记为 (p, q),其中 p 是 ')' 的个数,q 是 '(' 的个数。
考虑选了一些括号以后,怎么排列它们是最优的。可以用贪心来解决。
我们采用交换论证的方法来寻找排列方法。
假如 a,b 是相邻的且 a 在 b 前面,我们可以先将 a 的 '(' 和 b 的 ')' 匹配完,剩下新的一个 “)))(((” 型的串。
感性理解一下,我们应该剩下的东西越少越好。又因为 a 与 b 的括号总数不变,我们应该让 a 与 b 匹配尽量多的括号。匹配的括号个数就应该 \(=\min\{(个数,)个数\}\)
所以如果 \(\min\{a的(个数,b)个数\} > \min\{b的(个数, a的)个数\}\),则 a 就排在 b 前面。
可以发现上面那个东西是一直存在的,不会因为我们选的括号不同而变化。
所以我们可以先按照上面的法则排序,然后作一个简单的 dp 就可以了。
dp 的定义,以及状态转移留作习题。
@accepted code@
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 300;
const int INF = 1<<30;
struct node{
int p, q;
int num;
}a[MAXN + 5];// p -> ')', q -> '('
bool operator < (node a, node b) {
return min(a.q, b.p) > min(a.p, b.q);
}
char s[MAXN + 5];
int dp[2][MAXN*MAXN + 5];
int main() {
int n; scanf("%d", &n);
for(int i=1;i<=n;i++) {
scanf("%s", s);
int len = strlen(s);
for(int j=0;j<len;j++) {
if( s[j] == '(' ) a[i].q++;
else {
if( !a[i].q ) a[i].p++;
else a[i].q--, a[i].num += 2;
}
}
}
int tot = 0; sort(a+1, a+n+1);
for(int i=1;i<=n;i++) {
for(int j=0;j<=tot;j++)
dp[i&1][j] = dp[i&1^1][j];
for(int j=tot+1;j<=tot+a[i].q;j++)
dp[i&1][j] = -INF;
for(int j=a[i].p;j<=tot;j++)
dp[i&1][j-a[i].p+a[i].q] = max(dp[i&1][j-a[i].p+a[i].q], dp[i&1^1][j]+2*a[i].p+a[i].num);
tot += a[i].q;
}
printf("%d\n", dp[n&1][0]);
}
@details@
这道题让我想起了多校赛的某道题 HDU - 6299。
当初好像是随便乱蒙了一个贪心性质就过了 www。
@bzoj - 4922@ [Lydsy1706月赛]Karp-de-Chant Number的更多相关文章
- bzoj 4922: [Lydsy1706月赛]Karp-de-Chant Number 贪心+dp
题意:给定 $n$ 个括号序,让你从中选取一些括号序按照任意顺序拼接,最终生成一个合法的括号序列,求这个合法序列长度最大值. 题解:假设括号序列相对顺序固定,而我们要做的只是判断选还是不选的话可以转化 ...
- bzoj 4919 [Lydsy1706月赛]大根堆 set启发式合并+LIS
4919: [Lydsy1706月赛]大根堆 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 599 Solved: 260[Submit][Stat ...
- [BZOJ 4921][Lydsy1706月赛]互质序列
传送门 因为区间 gcd 的变换不会超过 log 个,所以我们可以暴力枚举区间起点,复杂度是 n*logn 的 #include <bits/stdc++.h> using namespa ...
- BZOJ 4919: [Lydsy1706月赛]大根堆 set启发式合并
这个和 bzoj 5469 几乎是同一道题,但是这里给出另一种做法. 你发现你要求的是一个树上 LIS,而序列上的 LIS 有一个特别神奇的 $O(n\log n) $ 做法. 就是维护一个单调递增的 ...
- BZOJ.4919.[Lydsy1706月赛]大根堆(线段树合并/启发式合并)
题目链接 考虑树退化为链的情况,就是求一个最长(严格)上升子序列. 对于树,不同子树间是互不影响的.仿照序列上的LIS,对每个点x维护一个状态集合,即合并其子节点后的集合,然后用val[x]替换掉第一 ...
- [BZOJ 4923][Lydsy1706月赛]K小值查询
传送门 势能分析平衡树,splay或treap都可以 放个指针版的就跑 #include <bits/stdc++.h> using namespace std; #define rep( ...
- BZOJ 4919: [Lydsy1706月赛]大根堆 启发式合并
我不会告诉你这是线段树合并的好题的... 好吧我们可以搞一个multiset在dfs时求出LIS(自带二分+排序)进行启发式合并,轻松加愉悦... #include<cstdio> #in ...
- BZOJ 4919: [Lydsy1706月赛]大根堆
F[x][i]表示x的子树中取的数字<=i的最大值,线段树合并优化DP 写得很难看,并不知道好看的写法 #include<cstdio> #include<algorithm& ...
- BZOJ 4919 [Lydsy1706月赛]大根堆 (SRM08 T3)
[题解] 求一个序列的LIS有一个二分做法是这样的:f[i]表示长度为i的上升序列中最后一个数最小可以是多少,每次二分大于等于当前数字x的f[j],把f[j]修改为x:如果找不到这样的f[j],那就把 ...
随机推荐
- cmd下带参数执行python文件
在一个文件下下创建程序代码, sys.argv 即后续cmd中需要传入的参数列表, sys.argv[0]即要执行的文件名 sys.argv[n]即参数的字符串 # -*- c ...
- Java处理正则验证手机号-详解
参考博客:https://www.cnblogs.com/wangzn/p/7212587.html https://www.cnblogs.com/go4mi/p/6426215.html pack ...
- 学习JDK1.8集合源码之--HashMap
1. HashMap简介 HashMap是一种key-value结构存储数据的集合,是map集合的经典哈希实现. HashMap允许存储null键和null值,但null键最多只能有一个(HashSe ...
- JSON和JSONP,原来ajax引用这个来实现跨域访问的
由于Sencha Touch 2这种开发模式的特性,基本决定了它原生的数据交互行为几乎只能通过AJAX来实现. 当然了,通过调用强大的PhoneGap插件然后打包,你可以实现100%的Socket通讯 ...
- HR招聘_(一)_招聘意识
最近接触到一点HR的工作,贯穿始终,故有点心得,与众人分享.言辞不尽之处,万望指点一二.不胜感激. HR招聘_(一)_招聘意识HR招聘_(二)_招聘方法论(招聘原因及原则) HR招聘_(三)_招聘方法 ...
- CSS中各种居中方法
CSS中各种居中方法,本文回顾一下,便于后续的使用. 水平居中方法 1.行内元素居中 行内元素居中是只针对行内元素的,比如文本(text).图片(img).按钮等行内元素,可通过给父元素设置 text ...
- java如何访问memcache
1 Memcache是什么 Memcache是danga.com的一个项目,最早是为 LiveJournal 服务的,目前全世界不少人使用这个缓存项目来构建自己大负载的网站,来分担数据库的 ...
- 多线程 多进程 协程 Queue(爬虫代码)
快速理解多进程与多线程以及协程的使用场合和特点 首先我们来了解下python中的进程,线程以及协程! 从计算机硬件角度: 计算机的核心是CPU,承担了所有的计算任务.一个CPU,在一个时间切片里只能运 ...
- 使用Git Bash进行代码管理
前提是已经安装了GitBash,这个稍后再出教程 1.新建一个目录,存放下载下来的项目,我在D盘新建了一个“gitspace”文件夹,用来存放下载下来的项目 2.进入刚刚新建的文件夹,即进入“gits ...
- 日期格式之——new Date()的用法
获取时间: 1 var myDate = new Date();//获取系统当前时间 获取特定格式的时间: 1 myDate.getYear(); //获取当前年份(2位) 2 myDate.getF ...