当前位置: 首页 > news >正文

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

括号序列:无聊,感觉做过类似的拼接类区间 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.fuzeviewer.com/news/1450/

相关文章:

  • 实验二 现代C++编程初体验
  • 周康阳精选冲刺省选国赛思维训练题
  • P3939 数颜色
  • 2025年压力容器厂家综合评测与选择指南
  • 项目构建优化:Make 与 Makefile
  • 11hhs
  • 在vue-markdown-render中解析LaTeX公式
  • CSP-S NOIP 2025 备考
  • ICPC Nanjing Regional (部分题题解)
  • 分布式锁巅峰对决:Redis RedLock vs ZooKeeper临时节点——Redission看门狗如何破解续期困局 - 教程
  • MySQL 数据加密整改文档(TDE + 字段加密 + 密码哈希)
  • 2025年火锅底料工厂厂家权威推荐榜单:袋装火锅底料/餐饮火锅底料/企业火锅底料源头厂家精选
  • 魔改frida
  • 2025年上海电动阀门厂最新推荐榜,气动阀门/高压阀门/真空阀门/自控阀门/调节阀门/聚焦产品实力与特色服务竞争力深度剖析
  • gmssl2.5常用命令
  • 云栖实录:重构可观测 - 打造大模型驱动的云监控 2.0 与 AIOps 新范式
  • 0289-KVS-读取目录中的文件
  • MySQL 安全审计日志保留与定期备份整改操作文档
  • MES 文摘
  • 从网页到桌面:自定义URL协议让应用无缝衔接
  • 第五届电子通信与计算机科学技术国际学术会议(ECCST 2025)
  • 2025 年精密无缝钢管、合金无缝钢管、高压锅炉无缝钢管厂家最新推荐,精准检测与稳定性能深度解析
  • 2025年分子动力学仿真厂家权威推荐榜单:动力学模拟/分子动力学模拟/粗粒化模拟源头厂家精选
  • 第十一届中国大学生程序设计竞赛 女生专场
  • ASP.NET Core WebApi 集成 MCP 协议完全指南
  • goldengate(ogg)日常维护
  • GNU C和ANSI C的一些差异
  • JAVA FX初次使用并制作辅助工具指南
  • CF1482E Skyline Photo
  • 2025年10月口碑好的板式家具厂家前十名推荐