@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的更多相关文章

  1. bzoj 4922: [Lydsy1706月赛]Karp-de-Chant Number 贪心+dp

    题意:给定 $n$ 个括号序,让你从中选取一些括号序按照任意顺序拼接,最终生成一个合法的括号序列,求这个合法序列长度最大值. 题解:假设括号序列相对顺序固定,而我们要做的只是判断选还是不选的话可以转化 ...

  2. bzoj 4919 [Lydsy1706月赛]大根堆 set启发式合并+LIS

    4919: [Lydsy1706月赛]大根堆 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 599  Solved: 260[Submit][Stat ...

  3. [BZOJ 4921][Lydsy1706月赛]互质序列

    传送门 因为区间 gcd 的变换不会超过 log 个,所以我们可以暴力枚举区间起点,复杂度是 n*logn 的 #include <bits/stdc++.h> using namespa ...

  4. BZOJ 4919: [Lydsy1706月赛]大根堆 set启发式合并

    这个和 bzoj 5469 几乎是同一道题,但是这里给出另一种做法. 你发现你要求的是一个树上 LIS,而序列上的 LIS 有一个特别神奇的 $O(n\log n) $ 做法. 就是维护一个单调递增的 ...

  5. BZOJ.4919.[Lydsy1706月赛]大根堆(线段树合并/启发式合并)

    题目链接 考虑树退化为链的情况,就是求一个最长(严格)上升子序列. 对于树,不同子树间是互不影响的.仿照序列上的LIS,对每个点x维护一个状态集合,即合并其子节点后的集合,然后用val[x]替换掉第一 ...

  6. [BZOJ 4923][Lydsy1706月赛]K小值查询

    传送门 势能分析平衡树,splay或treap都可以 放个指针版的就跑 #include <bits/stdc++.h> using namespace std; #define rep( ...

  7. BZOJ 4919: [Lydsy1706月赛]大根堆 启发式合并

    我不会告诉你这是线段树合并的好题的... 好吧我们可以搞一个multiset在dfs时求出LIS(自带二分+排序)进行启发式合并,轻松加愉悦... #include<cstdio> #in ...

  8. BZOJ 4919: [Lydsy1706月赛]大根堆

    F[x][i]表示x的子树中取的数字<=i的最大值,线段树合并优化DP 写得很难看,并不知道好看的写法 #include<cstdio> #include<algorithm& ...

  9. BZOJ 4919 [Lydsy1706月赛]大根堆 (SRM08 T3)

    [题解] 求一个序列的LIS有一个二分做法是这样的:f[i]表示长度为i的上升序列中最后一个数最小可以是多少,每次二分大于等于当前数字x的f[j],把f[j]修改为x:如果找不到这样的f[j],那就把 ...

随机推荐

  1. Java review-design pattern

    Design Patterns (Factory, Abstract Factory, singleton, DAO, Proxy): 1. Factory: In Factory pattern, ...

  2. Hibernate中的Query

    //1:创建query对象,方法里面写hql语句 Query query = session.createQuery("from User"); //2:利用query对象中的方法 ...

  3. WAP网站的推广方式(自整合篇)

    WAP网站推广随着无线互联时代的到来,已经日益受到大家的重视.虽然WAP网站的目前盈利模式还不是很清晰,但WAP网站推广的竞争强度将肯定会越来越激烈,下面和大家一起探讨下WAP网站的推广方法. 方法/ ...

  4. Django静态文件以及模板文件的配置 jQuery v1.12.4

    1.配置模板的路径 TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os. ...

  5. C#中的事件注册和注销

    C#中的事件注册和注销 由于.NET框架对消息循环机制进行了很好的封装,开发人员不再需要深入的了解Windows事件/消息实现的具体机制,也无需创建复杂的事件结构体和所谓的消息句柄.我们所要做的无非就 ...

  6. 【python爬虫】加密代理IP的使用与设置一套session请求头

    1:代理ip请求,存于redis: # 请求ip代理连接,更新redis的代理ip def proxy_redis(): sr = redis.Redis(connection_pool=Pool) ...

  7. Python学习笔记(三)Python基本数字类型及其简单操作(1)

    一.数字类型 表示数字或数值的数据类型称为数字类型,Python语言提供3种数字类型:整数.浮点数和复数,分别对应数学中的整数.实数和复数,下面就一起来了解一下他们吧! 1.整数类型 整数类型与数学中 ...

  8. python编写购物车小程序

     #练习#程序购物车#启动程序后,让用户输入工资,  然后打印商品列表,允许用户根据商品编号购买商品用户选择商品后 #检测余额是否够,够就直接扣款,不够就提醒可随时退出,退出时,打印已购买商品和余额  ...

  9. python之高阶函数--map()和reduce()

    以下为学习笔记:来自廖雪峰的官方网站 1.高阶函数:简单来说是一个函数里面嵌入另一个函数 2.python内建的了map()和reduce()函数 map()函数接收两参数,一个是函数,一个是Iter ...

  10. golang之下载安装配置

    1.下载:根据操作系统和计算架构选择合适的安装包,操作系统类型有linux.mac.windows等,计算架构分为32位的386计算架构和64位的amd64计算架构 2.安装:推荐安装到 /usr/l ...