【cf1272】F. Two Bracket Sequences

传送门

题意:
给出\(s,t\)两个合法括号序列,现在找到一个长度最小的合法的序列\(p\),使得\(s,t\)都为其子序列。

思路:

  • 考虑\(dp:dp[i][j][d]\)表示第一个串在\(i\),第二个串在\(j\),答案串左括号和右括号之差为\(d\)时的最短长度。
  • 那么转移时枚举下一位转移即可。
  • 还需要考虑一点细节:若当前\(d=0\),但是下一位为)时,我们需要先\(dp[i][j][0]\)向\(dp[i][j][1]\)转移,即在答案串中添加一个(来匹配。
  • 最后的答案即为\(min\{dp[n][m][d]+d\}\),若\(d>0\)时,我们还需要在答案串后面添加\(d\)个)来使其合法。
  • 输出路径时转移时记录一下前驱,然后根据\(d\)来找到当前应为哪个括号。

代码如下:

/*
 * Author:  heyuhhh
 * Created Time:  2019/12/13 11:40:50
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 200 + 5;

struct node {
    int i, j, k;
};

node pre[N][N][N << 1];
int dp[N][N][N << 1];
int n, m;
char s[N], t[N];

void run(){
    cin >> (s + 1) >> (t + 1);
    n = strlen(s + 1);
    m = strlen(t + 1);
    memset(dp, INF, sizeof(dp));
    dp[0][0][0] = 0;
    for(int i = 0; i <= n; i++) {
        for(int j = 0; j <= m; j++) {
            if(i == n && j == m) break;
            for(int k = 0; k < N; k++) if(dp[i][j][k] != INF) {
                if(s[i + 1] == t[j + 1]) {
                    if(s[i + 1] == ')') {
                        if(k == 0) {
                            if(dp[i][j][k + 1] > dp[i][j][k] + 1) {
                                dp[i][j][k + 1] = dp[i][j][k] + 1;
                                pre[i][j][k + 1] = node {i, j, k};
                            }
                        }
                        if(dp[i + 1][j + 1][k - 1] > dp[i][j][k] + 1) {
                            dp[i + 1][j + 1][k - 1] = dp[i][j][k] + 1;
                            pre[i + 1][j + 1][k - 1] = node {i, j, k};
                        }
                    } else if(s[i + 1] == '(') {
                        if(dp[i + 1][j + 1][k + 1] > dp[i][j][k] + 1) {
                            dp[i + 1][j + 1][k + 1] = dp[i][j][k] + 1;
                            pre[i + 1][j + 1][k + 1] = node {i, j, k};
                        }
                    }
                } else {
                    if(s[i + 1] == ')') {
                        if(k == 0) {
                            if(dp[i][j][k + 1] > dp[i][j][k] + 1) {
                                dp[i][j][k + 1] = dp[i][j][k] + 1;
                                pre[i][j][k + 1] = node {i, j, k};
                            }
                        }
                        if(dp[i + 1][j][k - 1] > dp[i][j][k] + 1) {
                            dp[i + 1][j][k - 1] = dp[i][j][k] + 1;
                            pre[i + 1][j][k - 1] = node {i, j, k};
                        }
                    } else if(s[i + 1] == '(') {
                        if(dp[i + 1][j][k + 1] > dp[i][j][k] + 1) {
                            dp[i + 1][j][k + 1] = dp[i][j][k] + 1;
                            pre[i + 1][j][k + 1] = node {i, j, k};
                        }
                    }
                    if(t[j + 1] == ')') {
                        if(k == 0) {
                            if(dp[i][j][k + 1] > dp[i][j][k] + 1) {
                                dp[i][j][k + 1] = dp[i][j][k] + 1;
                                pre[i][j][k + 1] = node {i, j, k};
                            }
                        }
                        if(dp[i][j + 1][k - 1] > dp[i][j][k] + 1) {
                            dp[i][j + 1][k - 1] = dp[i][j][k] + 1;
                            pre[i][j + 1][k - 1] = node {i, j, k};
                        }
                    } else if(t[j + 1] == '(') {
                        if(dp[i][j + 1][k + 1] > dp[i][j][k] + 1) {
                            dp[i][j + 1][k + 1] = dp[i][j][k] + 1;
                            pre[i][j + 1][k + 1] = node {i, j, k};
                        }
                    }
                }
            }
        }
    }
    int Min = INF;
    node ans;
    for(int i = 0; i < N; i++) {
        if(dp[n][m][i] + i < Min) {
            Min = dp[n][m][i] + i;
            ans = node {n, m, i};
        }
    }
    //for(int i = 400; i < 410; i++) {
        //cout << dp[1][3][i] << '\n';
    //}
    string res = "";
    node now = ans, last;
    while(1) {
         last = pre[now.i][now.j][now.k];
         //dbg(now.i, now.j, now.k, dp[now.i][now.j][now.k]);
         if(last.k > now.k) res += ")";
         else res += "(";
         now = last;
         if(now.i == 0 && now.j == 0 && now.k == 0) break;
    }
    reverse(res.begin(), res.end());
    for(int i = 0; i < ans.k; i++) res += ")";
    cout << res << '\n';;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

原文地址:https://www.cnblogs.com/heyuhhh/p/12043634.html

时间: 2024-10-17 13:13:43

【cf1272】F. Two Bracket Sequences的相关文章

【CodeForces】F. Letters Removing

[题目]F. Letters Removing [题意]给定只含小写字母.大写字母和数字的字符串,每次给定一个范围要求删除[l,r]内的字符c(l和r具体位置随删除变动),求m次操作后的字符串.n<=2*10^5. [算法]树状数组+平衡树(set) [题解]因为坐标是序列变动后的,动态坐标可以转化为找到第l个存在的数字到第r个存在的数字之间的范围. 将序列中存在记为1,删除记为0,转化为找前缀和恰好为l和r的位置,这是树状数组的经典操作,详见这篇题解介绍的方法(简单的排名功能) 找到l和r在原

# codeforces 1272 F. Two Bracket Sequences(三维dp + bfs)

codeforces 1272 F. Two Bracket Sequences(三维dp + bfs) 题目大意 输入两个括号序列 s,t(不一定合法),你需要构造一个尽可能短的合法括号序列使得s,t 都是这个序列的子序列(子序列意味着不用连续) 解题思路 dp[i][j][k]表示匹配到s的第i个字符,匹配到t的第j个字符,并且此时(的个数比)多k个的时候的最小合法序列长度,k的上限是200(s和t中最多200个(或者)). 状态转移: 枚举答案合法序列的每一位是放置(或者) ? 放置(,如

【AtCoder】ARC092 D - Two Sequences

[题意]给定n个数的数组A和数组B,求所有A[i]+B[j]的异或和(1<=i,j<=n).n<=200000. [算法]二分+模拟 [题解]将答案分成(A[i]+B[j]-A[i]^B[j])的异或和 以及 A[i]^B[j]的异或和,即单独考虑进位(后面部分很好算). 二进制题目必须拆位,通过进位使第k位+1的数对必须满足 ( A[i] & ((1<<k)-1) ) + ( B[i] & ((1<<k)-1) ) >= (1<<

【LeetCode】187. Repeated DNA Sequences

Repeated DNA Sequences All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACGAATTCCG". When studying DNA, it is sometimes useful to identify repeated sequences within the DNA. Write a function to find all

【python】f.write()写入中文出错解决办法

一个出错的例子 #coding:utf-8 s = u'中文' f = open("test.txt","w") f.write(s) f.close() 原因是编码方式错误,应该改为utf-8编码 解决方案一: #coding:utf-8 s = u'中文' f = open("test.txt","w") f.write(s.encode("utf-8")) f.close() 解决方案二: #codi

【NBUToj】1667 - Hkhv Loves Sequences(模拟,严格递增子串)

[1667] Hkhv Loves Sequences 时间限制: 1000 ms 内存限制: 65535 K 问题描述 Hkhv has a sequence a, consisting of n integers. We'll call a sequence ai,ai+1,...,aj (1<= i<= j<= n) a subsegment of the sequence a. The value (j-i+1) denotes the length of the subsegm

MT【248】$f(x)=\dfrac{1}{x-1}+\dfrac{1}{x-b}$的性质

探讨函数$f(x)=\dfrac{1}{x-a}+\dfrac{1}{x-b}$其中$a<b$的几个性质 分析:对称性:关于$(\dfrac{a+b}{2},0)$证明提示:$f(x)+f(a+b-x)=0$且定义域关于$(\dfrac{a+b}{2},0)$对称单调性:单调递减区间$(-\infty,a),(a,b),(b,+\infty)$,证明提示:用单调性的定义渐进性:$\lim\limits_{x\rightarrow-\infty}f(x)=0$;$\lim\limits_{x\ri

【hdu4734】F(x)-数位DP

题目描述: For a decimal number x with n digits (AnAn-1An-2 ... A2A1), we define its weight as F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1.  Now you are given two numbers A and B,  please calculate how many numbers are there between 0 and B, in

【贪心】cf1144G. Two Merged Sequences

题目分析 打算去cf写写大致题解: There might be another greedy algorithm using LIS/LDS which is more easier to make sense(it doesn't need swapping): To the first element $a_1$,it belongs to the increasing/decreasing sequence.Let's only consider it's in the increasi