Luogu P7914 [CSP-S 2021] 括号序列 题解 [ 蓝 ] [ 区间 DP ] [ 前缀和优化 ] [ 调试技巧 ]

news/2025/10/28 19:59:03/文章来源:https://www.cnblogs.com/zhr0102/p/19172612

括号序列:无聊,感觉做过类似的拼接类区间 DP 就直接秒了。

注意到这个超级括号序列定义很复杂,除了两边没有 \(\texttt{*}\) 没有啥很好的性质。于是直接考虑暴力区间 DP:定义 \(dp_{l, r}\) 表示 \(l\sim r\) 的合并方案数。

因为是拼接类区间 DP,所以还需要定义一个辅助转移数组 \(g_{l, r}\),表示将 \(l\sim r\) 合成到一个括号内的方案数。

剩下的就是些无聊的转移了,我们根据题面上的定义分别计数:

  • 规则 \(1\)
    • 直接枚举区间预处理 \(dp, g\) 的初值即可。
  • 规则 \(3\):需要特判区间两边是否能被设为括号。
    • (A):从 \([l + 1, r - 1]\) 处转移 \(dp, g\) 即可。
    • (SA):枚举左侧的 S 转移 \(dp, g\)
    • (AS):同理。
  • 规则 \(2\)
    • AB:拼接类区间 DP 板子,将转移划分为拼接左侧的整段,利用 \(g\) 数组转移即可。
    • ASB:同理,只是多了个后缀和优化而已。

直接 DP,时间复杂度 \(O(n^3)\)

一个计数题调试小技巧 from Lucyna_Kushinada,让我们膜拜他!!!1:

在 DP 转移的时候记录每个 DP 值存的方案,重载运算符并利用 vector 转移。可以比较直观地调试重复和漏掉的计数。

#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long ll;
using pi = pair<int, int>;
const int N = 505;
const ll mod = 1e9 + 7;
ll n, m, dp[N][N], suf[N], mxlen[N], g[N][N];
char s[N];
void add(ll &x, ll v)
{x += v;if(x >= mod) x -= mod;
}
int main()
{// freopen("bracket.in", "r", stdin);// freopen("bracket.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n >> m >> s + 1;// 预处理每个 DP 的初始值、每个位置的最长延伸值,即第一条规则for(int i = 1; i <= n; i++){for(int j = i + 1; j <= n; j++){bool legal = 1;if(!(s[i] == '(' || s[i] == '?')) legal = 0;if(!(s[j] == ')' || s[j] == '?')) legal = 0;for(int k = i + 1; k < j; k++)if(!(s[k] == '*' || s[k] == '?'))legal = 0;if(j - i + 1 - 2 > m) legal = 0;dp[i][j] = legal;g[i][j] = legal;}mxlen[i] = i - 1;for(int j = i; j <= n; j++){if(!(s[j] == '*' || s[j] == '?')) break;if(j - i + 1 > m) break;mxlen[i] = j;}}// 进行转移for(int len = 3; len <= n; len++){for(int l = 1; l + len - 1 <= n; l++){int r = l + len - 1;if((s[l] == '(' || s[l] == '?') && (s[r] == ')' || s[r] == '?')){// (A)add(dp[l][r], dp[l + 1][r - 1]);add(g[l][r], dp[l + 1][r - 1]);// (SA)bool legal = 1;for(int i = l + 1; i <= r - 2; i++){legal &= (s[i] == '*' || s[i] == '?');legal &= (i - l <= m);if(!legal) break;add(dp[l][r], dp[i + 1][r - 1]);add(g[l][r], dp[i + 1][r - 1]);}// (AS)legal = 1;for(int i = r - 1; i >= l + 2; i--){legal &= (s[i] == '*' || s[i] == '?');legal &= (r - i <= m);if(!legal) break;add(dp[l][r], dp[l + 1][i - 1]);add(g[l][r], dp[l + 1][i - 1]);}}// AB,要求 A 为整段for(int i = l + 1; i <= r - 1; i++)add(dp[l][r], g[l][i] * dp[i + 1][r] % mod);// ASB,要求 A 为整段memset(suf, 0, sizeof(suf));for(int i = r; i >= l; i--){suf[i] = suf[i + 1];add(suf[i], dp[i][r]);}for(int i = l + 1; i <= r - 2; i++){int rx = mxlen[i + 1];if(rx == i) continue;rx = min(rx, r - 1);ll tmp = g[l][i] * (suf[i + 2] - suf[rx + 2]) % mod;tmp = ((tmp % mod) + mod) % mod;add(dp[l][r], tmp);}}}cout << dp[1][n];return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/949101.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

扩展BaseMapper类 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

《程序员修炼之道:从小工到专家》前五分之二观后感

读完《程序员修炼之道:从小工到专家》前五分之二的内容,我对“程序员如何成长”有了更清晰的认知。书中开篇便强调“职业主义”,打破了我对“码农”的刻板印象——程序员不应只是被动执行需求的工具人,而应像匠人般…

矩阵快速幂章节笔记(这里主要介绍的是我的错题)

矩阵加速的递推 1.1维k阶 f(n)=f(n-1)+f(n-2)+f(n-i)可以添加系数 那么矩阵的第一列就是系数了,其它用未知数,然后计算。注意start数组,就是开始的数组是倒着来的,请看代码(斐波那契) 2.k维1阶 dp[i][j]=dp[i-…

实验二 现代C++编程初体验

任务一: 代码:#pragma once#include <string>// 类T: 声明 class T { // 对象属性、方法 public:T(int x = 0, int y = 0); // 普通构造函数T(const T &t); // 复制构造函数T(T &&t); //…

P5322 [BJOI2019] 排兵布阵

P5322 [BJOI2019] 排兵布阵 题解题目传送门 博客传送门 我们浏览一遍测试点,发现了一个 \(s=1\) 的特殊性质。先考虑这一性质。 \(s=1\)特殊性质 如果我们当前第 \(i\) 座城市的兵力数量足够时,添加兵力显然不优。而…

题解:P9292 [ROI 2018] Robomarathon

题目传送门 题目大意: 有 \(N\) 名机器人选手参加马拉松,选手编号为 \(1 \dots N\),分道编号也为 \(1 \dots N\)。选手 \(i\) 占据分道 \(i\),跑完全程需要 \(a_i\) 秒。设 \(S \subseteq \{1, 2, \dots, N\}\) 表…

[题解]P5322 [BJOI2019] 排兵布阵

P5322 [BJOI2019] 排兵布阵 我们可以预处理出第 \(i\) 个城堡分配 \(j\) 的兵力能获得多少的得分,记为 \(w[i][j]\)。 则每一个 \(w[i]\) 都是一个泛化物品,即价值(\(w[i][j]\))随着分配体积(\(j\))变化的物品。…

申威服务器安装Nacos 2.0.3 RPM包详细步骤(Kylin V10 sw_64架构)​附安装包

申威服务器安装Nacos 2.0.3 RPM包详细步骤(Kylin V10 sw_64架构)​附安装包​ Nacos 2.0.3-1.ky10.sw_64.rpm​ 是专为 ​申威(SW)架构​ 处理器,并运行 ​中标麒麟操作系统 Kylin V10(64位)​​ 的服务器环境定…

ZKY精选冲刺省选国赛仿真训练题

求和 QOJ - 9902 解题思路 代码实现点击查看代码Bridges AtCoder - arc143_d 解题思路 代码实现点击查看代码龙门考古 UniversalOJ - 840 解题思路 代码实现点击查看代码Discrete Centrifugal Jumps CodeForces - 1407…

MySQL 查询与更新语句执行过程深度解析:从原理到实践​ - 指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

ZKY精选冲刺省选国赛技巧训练题

Discrete Centrifugal Jumps CodeForces - 1407D 解题思路 代码实现点击查看代码序列妙妙值 UniversalOJ - 549 解题思路 代码实现点击查看代码Constrained Sums AtCoder - abc277_h 解题思路 代码实现点击查看代码ag…

逆向基础--编码(001)

逆向基础--编码(001)一.位与字节比特(Bit):1比特就是1位,每个0或1就是一个位,位是数据存储的最小单位。位是二进制表示,8位二进制是一个字节。 8位二进制(就是8个比特)最大:11111111字节(Byte):字节是通过网…

20251027 - 倍增 ST表

前言: 怎么标题改来改去的? 概念 因为每一个整数都可以转换成对应的二进制,所以可以表示成 \(a_0 \times 2^0 + a_1 \times 2 ^ 1 + a_2 \times 2 ^ 2 + a_{len} \times 2 ^ {len}\)。 因此,对于求跳 \(x\) 步后的…

周康阳精选冲刺省选国赛思维训练题

agc052_a Long Common Subsequence 解题思路 代码实现点击查看代码agc052_a Long Common Subsequence 解题思路 代码实现点击查看代码agc052_a Long Common Subsequence 解题思路 代码实现点击查看代码agc052_a Long C…

Luogu P7913 [CSP-S 2021] 廊桥分配 题解 [ 绿 ] [ 贪心 ] [ 前缀和 ] [ STL ]

廊桥分配 笑点解析:VP 的时候想这题想了 20min,比想 T3 的时间长。 关键结论:在不考虑廊桥限制的情况下,给每个飞机分配一个最小的廊桥编号。当最终廊桥数目大于等于其对应编号时,飞机才能被分配到廊桥。 理解起来…

10-27 CSP 赛前比赛记录

DNA 序列(DNA)哈希题啊,但是忘了怎么写哈希了 qwq,所以…… 思路大概就是维护一个长度为 \(k\) 的四进制数,类似于一个滑动窗口,就是除以 \(4\) 后加上右边新加的数乘上 \(4^k\),就可以得到其对应的哈希值,取模…

P3939 数颜色

这道题是暑假写的。但是当时数据结构学傻了,写了个莫队。 然后刚刚发现没过,连忙重新看题。 想了想发现跟可以跟Ynoi有一道区间众数题一个思路处理一下,直接二分就完了。 就记录一下每个数的出现次数。这里还有个小…

完整教程:Docker 搭建 Nginx 并启用 HTTPS 具体部署流程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

AI开发微信小程序-有感

我先有一版html代码(有一个个人网站,里面都是一些在线使用的工具) 抽取出了其中一个小功能,让AI根据现有html代码直接转成小程序 直接拿过来在微信小程序开发IDE上,进行测试 稍微调整一下,就OK了。 AI真的是太有…