P7914 [CSP-S 2021] 括号序列
简要题意
给定 \(k\),定义 “超级括号序列”(简称括号序列,下同) 字符串为:
- 仅由
( ) *三种字符组成。 - 下面令 \(S\) 为不超过 \(k\) 个 \(\ast\) 字符拼接而成的字符串(\(S\) 可以为空字符串)。
- \(\text{(S)}\) 是括号序列。
- 如果 \(A\) 是括号序列,\(\text{(AS)},\text{(SA)}\) 都是括号序列。
- 如果 \(A,B\) 是括号序列,则 \(\text{ASB}\) 是括号序列。
- 特别的,空字符串不是括号序列。
例如,若 \(k = 3\),则字符串 \(\text{((**()*(*))*)(***)}\) 是括号序列,但字符串 \(\text{*()}\)、\(\text{(*()*)}\)、\(\text{((**))*)}\)、\(\text{(****(*))}\) 均不是。
给你一个长度为 \(n\) 的括号序列 \(s\),有的字符已经确定,有的字符尚未确定(用 \(\text{?}\) 替代)。求该字符串将所有尚未确定的字符一一确定的方法,使得得到的字符串是一个括号序列?对 \(10^{9}+7\) 取模。
对于 \(100 \%\) 的数据,\(1 \le k \le n \le 500\)。
思路
非常神仙的区间 DP 题。
状态设计
先设状态:
- \(f[l][r][0]\) 为 \([l,r]\) 为 \(S\) 型字符串的个数。如
********。 - \(f[l][r][1]\) 为 \([l,r]\) 为被匹配的括号包裹的字符串个数。如
(*(*(*))*)。 - \(f[l][r][2]\) 为 \([l,r]\) 为以括号序列开头,\(\ast\) 结尾的字符串个数。如
(*(*)*)***(*)*。 - \(f[l][r][3]\) 为 \([l,r]\) 为以括号序列开头与结尾的字符串个数,包含 \(f[l][r][2]\)。
- \(f[l][r][4]\) 为 \([l,r]\) 为以括号序列结尾,\(\ast\) 开头的字符串个数,如
****(*(***))。 - \(f[l][r][5]\) 为 \([l,r]\) 为以 \(\ast\) 开头或结尾的个数,包含 \(f[l][r][0]\)。
状态转移
\begin{aligned}
& f[l][r-1][0] & \operatorname{ast}(r)\\
& 0 & \text{otherwise}
\end{aligned}
\right.
\]
解释:\(\operatorname{ast}(r)\) 指 \(s_r\) 可能为 \(\ast\)。如果不是 \(\ast\) 自然没有了。
\begin{aligned}
& (f[l+1][r-1][0]+f[l+1][r-1][2]+f[l+1][r-1][3]+f[l+1][r-1][4])& \operatorname{match(l,r)} \\
& 0 & \text{otherwise}
\end{aligned}
\right.
\]
解释:\(\operatorname{match}(l,r)\) 为 \(s_l,s_r\) 可能括号匹配。加括号的时候,除了两边都是 \(\ast\) 且中间有括号序列外,其他都可以。
&f[l][r][2]=\sum_{i=l}^{r-1}f[l][i][3]\cdot f[i+1][r][0] \\
&f[l][r][3]=(\sum_{i=l}^{r}(f[i+1][r]\cdot (f[l][i][2]+f[l][i][3]))+f[l][r][1]) \\
&f[l][r][4]=\sum_{i=l}^{r}f[i+1][r][1]\cdot (f[l][i][4]+f[l][i][5]) \\
&f[l][r][5]=(\sum_{i=l}^{r}f[l][i][4]\cdot f[i+1][r][0])+f[l][r][0]
\end{aligned}
\]
- \(f[l][r][2]\) 中是括号序列开头(3)接 \(\ast\)(0)
- \(f[l][r][3]\) 可以是 2,3 开头,必须是 0 结尾
- \(f[l][r][4]\) 可以是4,5 开头,必须是 1 结尾
- \(f[l][r][5]\) 可以是4 开头,0 结尾。
最后答案就是 \(f[1][n][3]\)。
时间复杂度 \(O(n^3)\)。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int f[505][505][10];
char s[505];
int n,k;
const int MOD = 1e9+7;
inline bool is_star(int pos){
return (s[pos]=='*'||s[pos]=='?');
}
inline bool is_left_bracket(int pos){
return (s[pos]=='('||s[pos]=='?');
}
inline bool is_right_bracket(int pos){
return (s[pos]==')'||s[pos]=='?');
}
inline bool is_brackets_matched(int left,int right){
return is_left_bracket(left)&&is_right_bracket(right);
}
int m(int x){return (x%MOD+MOD)%MOD;}
void M(int &x){x=m(x);}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n>>k;
cin>>(s+1);
for(int i=1;i<=n;i++){
f[i][i-1][0]=1;
}
for(int length=1;length<=n;length++){
for(int l=1,r=length;l<=n&&r<=n;l++,r++){
// 处理情况 0
if(length<=k && f[l][r-1][0] && is_star(r))f[l][r][0]=1;
else f[l][r][0]=0;
// 处理情况 1
if(length>1 && is_brackets_matched(l,r)){
f[l][r][1]=m(f[l+1][r-1][0]+f[l+1][r-1][2]+f[l+1][r-1][3]+f[l+1][r-1][4]);
}
// 处理情况 2
if(length>1){
for(int i=l;i<r;i++){
f[l][r][2] += m(f[l][i][3]*f[i+1][r][0]);
M(f[l][r][2]);
}
}
// 处理情况 3
if(length>1){
for(int i=l;i<r;i++){
f[l][r][3] += m(m(f[l][i][2]+f[l][i][3])*f[i+1][r][1]);
M(f[l][r][3]);
}
}
f[l][r][3] += f[l][r][1];M(f[l][r][3]);
// 处理情况 4
if(length>1){
for(int i=l;i<r;i++){
f[l][r][4] += m(m(f[l][i][4]+f[l][i][5])*f[i+1][r][1]);
M(f[l][r][4]);
}
}
// 处理情况 5
if(length>1){
for(int i=l;i<r;i++){
f[l][r][5] += m(f[l][i][4]*f[i+1][r][0]);
M(f[l][r][5]);
}
}
f[l][r][5]+=f[l][r][0];M(f[l][r][5]);
}
}
cout<<m(f[1][n][3]);
return 0;
}
P7914 [CSP-S 2021] 括号序列的更多相关文章
- 上午小测3 T1 括号序列 && luogu P5658 [CSP/S 2019 D1T2] 括号树 题解
前 言: 一直很想写这道括号树..毕竟是在去年折磨了我4个小时的题.... 上午小测3 T1 括号序列 前言: 原来这题是个dp啊...这几天出了好几道dp,我都没看出来,我竟然折磨菜. 考试的时候先 ...
- BZOJ4350: 括号序列再战猪猪侠
Description 括号序列与猪猪侠又大战了起来. 众所周知,括号序列是一个只有(和)组成的序列,我们称一个括号 序列S合法,当且仅当: 1.( )是一个合法的括号序列. 2.若A是合法的括号序列 ...
- DP专题——括号序列
毕竟是个渣,写完一遍之后又按LRJ的写了一遍,再写了一遍递归版,最终加上输出解部分 括号序列 定义如下规则序列(字符串): 空序列是规则序列: 如果S是规则序列,那么(S)和[S]也是规则序列: 如果 ...
- 【BZOJ】2209: [Jsoi2011]括号序列(splay)
http://www.lydsy.com/JudgeOnline/problem.php?id=2209 splay又犯逗........upd1那里的sum忘记赋值反............. 本题 ...
- 51nod1476 括号序列的最小代价
这题应该可以用费用流写吧?不过我想不出贪心来TAT.其实还是单调队列乱搞啊T_T //ÍøÉϵÄ̰ÐÄËã·¨ºÃÉñ°¡¡£¡£¡£ÎÒÖ»»áÓÃ×îС·ÑÓÃ×î´óÁ÷ÅÜTAT #in ...
- lintcode: 有效的括号序列
题目: 有效的括号序列 给定一个字符串所表示的括号序列,包含以下字符: '(', ')', '{', '}', '[' and']', 判定是否是有效的括号序列. 样例 括号必须依照 "() ...
- uoj #31. 【UR #2】猪猪侠再战括号序列 贪心
#31. [UR #2]猪猪侠再战括号序列 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://uoj.ac/problem/31 Descript ...
- bzoj 1095 [ZJOI2007]Hide 捉迷藏(括号序列+线段树)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1095 [题意] 给定一棵树,树上颜色或白或黑而且可以更改,多个询问求最远黑点之间的距离 ...
- CODEVS 3657 括号序列
[问题描述] 我们用以下规则定义一个合法的括号序列: (1)空序列是合法的 (2)假如S是一个合法的序列,则 (S) 和[S]都是合法的 (3)假如A 和 B 都是合法的,那么AB和BA也是合法的 例 ...
随机推荐
- Vue学习之--------组件自定义事件(绑定、解绑)(2022/8/21)
文章目录 1.基础知识 2.代码实例 2.1 App.vue 2.2 school.vue 2.3 student.vue 3.测试效果(略) 4.实际应用(在组件化编码实战三的基础上改进) 4.1 ...
- Redis 01: 非关系型数据库 + 配置Redis
数据库应用的发展历程 单机数据库时代:一个应用,一个数据库实例 缓存时代:对某些表中的数据访问频繁,则对这些数据设置缓存(此时数据库中总的数据量不是很大) 水平切分时代:将数据库中的表存放到不同数据库 ...
- AgileBoot - 如何集成内置数据库H2和内置Redis
本项目地址: github: https://github.com/valarchie/AgileBoot-Back-End gitee: https://gitee.com/valarchie/Ag ...
- JavaScript的异步编程之Promise
Promise 一种更优的异步编程统一 方法,如果直接使用传统的回调函数去完成复杂操作就会形成回调深渊 // 回调深渊 $.get('/url1'() => { $.get('/url2'() ...
- 记录在linux上单机elasticsearch8和kibana8
目录 1.背景 2.es对jdk和操作系统的要求等 3.安装步骤 3.1 下载对应版本的es 3.2 创建es账户 3.3 修改es配置 3.3.1 修改es配置 3.3.3 修改jvm配置 3.4 ...
- Qt--无边框窗口完美(FrameLess)实现,包含缩放和移动功能重写。
前言 Qt原本的窗口虽然可以通过QSS样式进行美化,但是只是对客户区有用,对于客户区是无效的.所以想做出一个比较好看的程序,还得自己重写实现无边框窗口. Qt实现无边框其实一句代码就可以,但是窗口自带 ...
- 小菜鸡学习---<正则表达式学习笔记2>
正则表达式学习笔记2 一.修饰符 前面我们学习的都是用于匹配的基本的关键的一些表达式符号,现在我们来学习修饰符.修饰符不写在正则表达式里,修饰符位于表达式之外,比如/runoob/g,这个最后的g就是 ...
- C# 窗体相关知识
一 窗体 固定窗体大小,并不能最大/最小化: FormBorderStyle属性设置为:FixedSingleMaximizeBox = falseMinimizeBox = false都是在For ...
- Seata 1.5.2 源码学习
文章有点长,我决定用半个小时来给您分享~ 基于Seata 1.5.2,项目中用 seata-spring-boot-starter 1. SeataDataSourceAutoConfiguratio ...
- 学习ASP.NET Core Blazor编程系列十——路由(中)
学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...