首页 > 其他分享 >[dp 记录]szjudge#26 括号序列

[dp 记录]szjudge#26 括号序列

时间:2022-11-06 17:13:29浏览次数:38  
标签:26 szjudge int 括号 include pn dp pm

dp 部分平凡,但是后面找最值是值得深思的。

题意:给出两个由左右括号形成的字符串,求在长度最小的基础上字典序最小的合法括号序列,使给出字符串均为其子串。\(|s|,|t| \leq 300\)。

首先看着非常 dp。因为有子序列,需要把匹配几位塞进 dp 状态。接着因为括号序列要合法,要把当前几个未闭合左括号塞进 dp 状态中。前两维相同时第三维间还有转换,那就把长度也塞进去。信息好多啊,甚至只需要开成 bool 数组。然后好像就不行了。\(O(n^4)\) 跑 \(300\),怎么可能。

\(dp_{i,j,k,l}\):与 \(s\) 匹配 \(i\) 位,\(t\) 匹配 \(j\) 位,剩余 \(k\) 个未闭合左括号,当前长度为 \(l\),是否可行。

转移:

\[\begin{aligned} dp_{i+[s_i=')'],j+[s_j=')'],k-1,l+1} &\gets& dp_{i,j,k,l} \\ dp_{i+[s_i='('],j+[s_j='('],k+1,l+1} &\gets& dp_{i,j,k,l} \end{aligned} \]

赛时就想到这里了。不想写,不想调,GG。

究其原因,是 dp 设的东西太多了。好像只要最小化长度啊,为什么要把长度的所有情况的是否合法都塞进去,存个最小长度不就行了。

把第四位压掉 dp 改成 int 类型,前三维表意不变,然后会发现转移混乱。原来有 \(l\) 一定增大的条件,可以按 \(l\) 枚举,现在好像没什么好的顺序啊。

那就不要用当前状态更新未来状态的方法了,枚举之前状态更新当前状态。

\[\begin{aligned} dp_{i,j,k} & \stackrel{\min}{\longleftarrow} & dp_{i-[s_i=')'],j-[s_j=')'],k+1}+1 \\ dp_{i,j,k,l} &\stackrel{\min}{\longleftarrow}& dp_{i-[s_i='('],j-[s_j='('],k-1}+1 \end{aligned} \]

注意到其实不一定 \(k=0\) 的状态才有用,可以手动在后补 \(k\) 个右括号来使其合法。容易发现这样子是最优情况。

长度限制解决了,那字典序呢?有 dp 数组了,可以回溯时优先回溯字典序小者来满足最优性。

但是 dp 是从后往前最优啊?那就把原字符串翻转一下,最前的数就到最后了。

为了让翻转后还能匹配,翻转后左右括号应交换位置。

然后就做完了。感觉这题不错,难度也不大,为什么没有人赛时做出来呢。

std 写得好漂亮,学到了一些 string 的新用法。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
const int M = 305;
int f[M][M][M];
int n, m, pi, pj, pt, pk; 
string a, b;
void chkmin(int &x, int y) {
    if(y < x) x = y;
}
string calc(int k, int n, int m) {
    if(k + n + m == 0) return "";
    int pn = n - (a[n] == ')'), pm = m - (b[m] == ')');
    if(f[k+1][pn][pm] + 1 == f[k][n][m]) return calc(k+1, pn, pm) + ')';
    pn = n - (a[n] == '('), pm = m - (b[m] == '(');
    return calc(k-1, pn, pm) + '(';
}
void rev(string &x) {
    int n = x.length();
    for(int i = 0; i < n/2; i++) swap(x[i], x[n - i - 1]);
    for(int i = 0; i < n; i++) x[i] = '(' + ')' - x[i];
}
int main(){
    std::ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> a >> b;
    n = a.length(); m = b.length();
    rev(a); rev(b);
    a = ' ' + a; b = ' ' + b;
    memset(f, 0x3f, sizeof(f));
    f[0][0][0] = 0;
    for(int i = 0; i <= n; i++) {
        for(int j = 0; j <= m; j++) {
            for(int k = 0; k <= max(n, m); k++) {
                int pn = i - (a[i] == ')'), pm = j - (b[j] == ')');
                chkmin(f[k][i][j], f[k+1][pn][pm] + 1);
                pn = i - (a[i] == '('), pm = j - (b[j] == '(');
                if(k) chkmin(f[k][i][j], f[k-1][pn][pm] + 1);
            }
        }
    }
    string ans = {(char)('(' + 10)};
    int mnlen = 998244353;
    for(int k = 0; k <= max(n,m); k++) {
        mnlen = min(mnlen, f[k][n][m] + k);
    }
    for(int k = 0; k <= max(n,m); k++) {
        if(mnlen == f[k][n][m] + k) ans = min(ans, calc(k, n, m) + string(k, ')'));
    }
    rev(ans);
    cout << ans << endl;
}

标签:26,szjudge,int,括号,include,pn,dp,pm
From: https://www.cnblogs.com/purplevine/p/16863039.html

相关文章

  • 批量给UDP_Server发消息
    Server端     客户端:  运行结果: ......
  • 计算机等级考试二级C语言上机题集(第26~30套)
    第26套1.程序填空题给定程序中,函数fun的功能是:计算 例如,若x=2.5,n=15时,函数值为:1.917915。请在下划线处填入正确的内容并将下划线删除,使程序得出正确的结果。注意:......
  • NOIP2017 逛公园 记忆化搜索|dp(已过hack数据)
    30pts可以发现,\(k=0\)的情况下,问题转化为最短路计数,即从起点\(s\)到每个点有多少最短路。跑最短路的时候顺便维护\(ans[u]\),表示从\(s\)到\(u\)的最短路方案,讨论如下:①......
  • JavaScript修改修改图片dpi
    欢迎关注前端早茶,与广东靓仔携手共同进阶​​​​前端早茶专注前端,一起结伴同行,紧跟业界发展步伐~ 一、原理changeDPI提供了2个实用函数,可以更改画布生成的图像的dpi,无......
  • JavaScript修改修改图片dpi
    欢迎关注前端早茶,与广东靓仔携手共同进阶​​​​前端早茶专注前端,一起结伴同行,紧跟业界发展步伐~ 一、原理changeDPI提供了2个实用函数,可以更改画布生成的图像的dpi,无......
  • Codeforces Round #826 (Div. 3) D. Masha and a Beautiful Tree(树+dfs)
    D.MashaandaBeautifulTree题目大意:给定一颗满二叉树的叶子节点,让我们更换子树位置,从而让叶子节点排序为升序求最小操作数,如果不能移动成那样的话,直接输出-1.in......
  • 数位dp例题
    怎么感觉这种dp有点过于板子 1. 某人命名了一种不降数,这种数字必须满足从左到右各位数字成小于等于的关系,如12245 问区间【l,r】内有多少个不降数。#include<ios......
  • 腾讯云Linux轻量服务器使用宝塔面板一键部署WordPress个人博客教程
    WordPress作为动态博客的代表,至今已经有十几年历史,而且一直在更新发展中,功能强大,插件和主题丰富,WordPress搭建使用也很方便。作为个人站长和博主,很多都是从WordPress入门......
  • 基于国产芯片RK1126的智能视频分析网关
    产品简介智能边缘计算网关力求打造一个开放式、可扩展、二次开发升级的智能型AI终端,硬件基于arm的CPU,2T算力的NPU,具备更低的功耗,更高的性能,同时扩展多路外围接口,如RS232、4......
  • Android实现UDP通信
    TCP和UDP的不同上次我们讲的是TCP的socket,他们之间的不同在于,tcp要等待客户端的接入,然后获得客户端socket然后进行IO操作,udp直接传送数据即可  图片来源:面试官:说说U......