Karp-de-Chant Number(BZOJ-4922) - 竞赛题解

进行了一次DP的练习,选几道题写一下博客~

标签:BZOJ / 01背包 / 贪心


『题目』

>> There!

给出 \(n\) 个括号字符串(只包含'(',')'),你需要从中选出一些字符串并对它们排序,使得它们连成一个字符串后构成一个匹配的字符串。求构成的字符串的最大长度~


『题解』

假如我们不考虑顺序,只考虑选择哪些字符串,我们很容易想到 dp[i][j] 表示在前 \(i\) 个字符串中选出一些字符串使得 左括号的个数-右括号的个数 为 \(j\)。那么显然结果就是 dp[n][0]~其实还挺像01背包

但是我们不得不考虑如何安排原来字符串的顺序——因为我们dp转移时字符串的顺序是有影响的(不难理解,在转移时,我们要时刻保持‘(’数量≥')'数量,但是假如第一个字符串是")))",第二个字符串是"(((",直接按这种顺序我们就没法选择)

这样我们需要确定一开始的字符串的顺序……还挺像一道贪心题。

我们先把一个字符串转换为一个结构体:

struct NODE{
int del, //左括号-右括号
Mindel, //对于字符串的每一个位置i,求出开头到i的左括号数量-右括号数量,Mindel是它们的最小值
len; //字符串长度
};

为什么要储存这些值?显然是有用的……

第一个贪心性质比较简单——按 \(del\) 从大到小排序,然后将 \(del\ge 0\) 和 \(del<0\) 分成前后两半。

第二个贪心是把前一半按 \(Mindel\) 从大到小排序。因为 \(Mindel\) 越大,就说明剩下来的左括号数量越多,那么就越能和接下来的右括号匹配(毕竟在转移时,我们允许暂时存在左括号数量>右括号数量,但是绝对不能右括号数量>左括号数量!)

第三个贪心是把后一半按 \(del-Mindel\) 从大到小排序。\(del-Mindel\) 是什么呢?如果我们把 \(del\) 也看成一个前缀和(也就是从开头到末尾的前缀和),那么 \(del-Mindel\) 就可以看成一个 后缀和 .显然对于字符串的第 \(i\) 个位置,\(1\)~\(i\) 的前缀和 加上 \(i+1\)~\(len\) 的后缀和 就是 \(del\) ,因为此时的前缀和最小,那么后缀和就最大。因为del<0,所以Mindel<0,也就是右括号比左括号多,则“后缀和大”说明 (右括号数量-左括号数量) 越小,其实就是多余的右括号越少。那么显然我们更容易让少量右括号与多余的左括号匹配,所以就按 \(del-Mindel\) 排序了。

接下来就类似一个 01背包 的过程了——

\[dp[i][j]=\begin{cases}
\min(dp[i-1][j],dp[i-1][j-del]+len)\ \ \ \ |\ j\ge del , j-del+Mindel\ge 0\\
dp[i-1][j]\ \ \ |\ else
\end{cases}
\]

至于“\(j-del+Mindel\ge 0\)” 就是说如果要选择第 \(i\) 个字符串,那么它对 \(j\) 的贡献应该是 \(del\) ,所以 \(j-del\) 就是上一次没有选择第 \(i\) 个字符串时的 \(j\) 。再加上 \(Mindel\) 就是连接上第 \(i\) 个字符串后从左到右计算 左括号-右括号 的最小值,如果它为负数,那么就存在一个位置到开头的 左括号 比 右括号 少,就不合法!

稍微一点细节就是注意判断 \(j-del\) 过后会不会数组越界的问题了~


『源代码』

/*Lucky_Glass*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=300;
struct NODE{
int del,Mindel,len;
// NODE(){Mindel=(1<<30);}
}nod[N+7];
bool cmp1(NODE A,NODE B){return A.del>B.del;}
bool cmp2(NODE A,NODE B){return A.Mindel>B.Mindel;}
bool cmp3(NODE A,NODE B){return A.del-A.Mindel>B.del-B.Mindel;}
int n,Maxdel;
int dp[N+7][N*N+7];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
char str[N+7]="";
scanf("%s",str);
nod[i].len=strlen(str);
for(int j=0;j<nod[i].len;j++)
nod[i].del+=(str[j]=='('? 1:-1),
nod[i].Mindel=min(nod[i].Mindel,nod[i].del),
Maxdel+=(str[j]=='('? 1:0);
}
sort(nod+1,nod+n+1,cmp1);
int pos=n+1;
for(int i=1;i<=n;i++)
if(nod[i].del<0){
pos=i;
break;
}
sort(nod+1,nod+pos,cmp2);
sort(nod+pos,nod+n+1,cmp3);
memset(dp,200,sizeof dp);
dp[0][0]=0;
for(int i=1;i<=n;i++){
for(int j=0;j<=Maxdel;j++){
dp[i][j]=dp[i-1][j];
if(j-nod[i].del>=0 && j-nod[i].del<=Maxdel && j-nod[i].del+nod[i].Mindel>=0)
dp[i][j]=max(dp[i][j],dp[i-1][j-nod[i].del]+nod[i].len);
}
}
printf("%d\n",dp[n][0]);
return 0;
}

\(\mathcal{The\ End}\)

\(\mathcal{Thanks\ For\ Reading!}\)

关于博客里面的问题各位可以在 \(lucky\_glass@foxmail.com\) e-mail一下~

竞赛题解 - Karp-de-Chant Number(BZOJ-4922)的更多相关文章

  1. 《ACM国际大学生程序设计竞赛题解Ⅰ》——基础编程题

    这个专栏开始介绍一些<ACM国际大学生程序设计竞赛题解>上的竞赛题目,读者可以配合zju/poj/uva的在线测评系统提交代码(今天zoj貌似崩了). 其实看书名也能看出来这本书的思路,就 ...

  2. 竞赛题解 - Broken Tree(CF-758E)

    Broken Tree(CF-758E) - 竞赛题解 贪心复习~(好像暴露了什么算法--) 标签:贪心 / DFS / Codeforces 『题意』 给出一棵以1为根的树,每条边有两个值:p-强度 ...

  3. 竞赛题解 - Palisection(CF-17E)

    Palisection(CF-17E) - 竞赛题解 Manacher学到一定程度,也需要练一下有趣的题了-- (这是多老的题了 \(QwQ\))[传送门] 『题意』 给出一个字符串,求总共有多少对不 ...

  4. 竞赛题解 - NOIP2018 保卫王国

    \(\mathcal{NOIP2018}\) 保卫王国 - 竞赛题解 按某一个炒鸡dalao名曰 taotao 的话说: \(\ \ \ \ \ \ \ \ \ "一道sb倍增题" ...

  5. 竞赛题解 - [CF 1080D]Olya and magical square

    Olya and magical square - 竞赛题解 借鉴了一下神犇tly的博客QwQ(还是打一下广告) 终于弄懂了 Codeforces 传送门 『题目』(直接上翻译了) 给一个边长为 \( ...

  6. 竞赛题解 - CF Round #524 Div.2

    CF Round #524 Div.2 - 竞赛题解 不容易CF有一场下午的比赛,开心的和一个神犇一起报了名 被虐爆--前两题水过去,第三题卡了好久,第四题毫无头绪QwQ Codeforces 传送门 ...

  7. 竞赛题解 - NOIP2018 旅行

    \(\mathcal {NOIP2018} 旅行 - 竞赛题解\) 坑还得一层一层的填 填到Day2T1了 洛谷 P5022 题目 (以下copy自洛谷,有删减/修改 (●ˇ∀ˇ●)) 题目描述 小 ...

  8. 竞赛题解 - NOIP2018 赛道修建

    \(\mathcal {NOIP2018}\) 赛道修建 - 竞赛题解 额--考试的时候大概猜到正解,但是时间不够了,不敢写,就写了骗分QwQ 现在把坑填好了~ 题目 (Copy from 洛谷) 题 ...

  9. 竞赛题解 - Ikki's Story IV-Panda's Trick

    Ikki's Story IV-Panda's Trick - 竞赛题解 也算是2-sat学习的一个节点吧 终于能够自己解决一道2-sat的题了 ·题目 一个圆上有n个点按顺时针编号为 0~n-1 , ...

随机推荐

  1. Python基础-socket编程

    一.网络编程 自从互联网诞生以来,现在基本上所有的程序都是网络程序,很少有单机版的程序了. 计算机网络就是把各个计算机连接到一起,让网络中的计算机可以互相通信.网络编程就是如何在程序中实现两台计算机的 ...

  2. Python爬虫教程-19-数据提取-正则表达式(re)

    本篇主页内容:match的基本使用,search的基本使用,findall,finditer的基本使用,匹配中文,贪婪与非贪婪模式 Python爬虫教程-19-数据提取-正则表达式(re) 正则表达式 ...

  3. Linux 下载百度网盘大文件

    Linux 下没有百度网盘客户端,用浏览器下载速度慢得急死人 鼠标移到链接处, 右键, 然后复制链接 接着在终端里输入 axel -n 50 -o filename.ext “粘贴链接到此处” axe ...

  4. redis 存取问题

    今天在写短信接口时候,要把验证码存到缓存里面.因为之前别人已经写的有案例,按照之前写的,获取 值.存到数据库,存到redis. 因为有过期时间,需要传过期时间.但是怎么都是不出来... 源码: @Ov ...

  5. Android学习——ListView的缓存机制

    在使用ListView的时候,需要加载适配器和数据源,这篇文章主要介绍一下ListView的使用以及利用ListView的缓存机制来减少系统的初始化时间. ListView的使用 ListView和V ...

  6. 【Leetcode】【Medium】Construct Binary Tree from Inorder and Postorder Traversal

    Given inorder and postorder traversal of a tree, construct the binary tree. Note:You may assume that ...

  7. Vim中增加ga键的vmap功能

    ga是Vim自带的显示光标字符编码的功能,但是反过来,没有从编码显示对应字符的功能. 因为编码是多位数,所以可视模式下写了此功能. 规则: 纯数字认为是10进制 其他情况都认为是16进制 纯数字的话, ...

  8. SAP S/4HANA销售订单创建时,会自动触发生产订单的创建

    这个自动触发的过程是怎么实现的? 使用下面的代码创建一个销售订单: DATA: ls_header TYPE bapisdhd1, ls_headerx TYPE bapisdhd1x, lt_bap ...

  9. 关于TCHAR和string对象的c.str()一些注意事项

    1.TCHAR 根据预处理器的设置,如果是_MBCS, 那么TCHAR = char: 如果 如果设置的是UNICODE和_UNICODE,那么TCHAR=wchar_t.就等于根据当前环境会选择不同 ...

  10. bootstrap table footerFormatter用法 统计列求和 sum、average等

    其实上一篇blog里已经贴了代码,简单解释一下吧: 1.showFooter: true,很重要,设置footer显示: $(cur_table).bootstrapTable({ url: '/et ...