Java && C++ 实现第十二届蓝桥杯 C++ B组 J括号序列

182 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情

虽然是C++组的,但是和Java组的差不了两道题,大家都可以看一看 如有错误,还请佬 评论或私信指出(写的稍些急) 再也不肝博客了 /(ㄒoㄒ)/~~

(由于上传图片有限制,如果描述不清楚点击手写题解) 手写题解字丑,但是小编感觉会比文字看的直观一些(其实是不会用数学公式)

编程题测试数据

C++B组手写题解(如果访问出错,请刷新访问的页面即可(Nebo的问题))

当前页面的编程题均在C语言网成功运行 C语言网有各届蓝桥杯的题库 第十二届蓝桥杯编程题测试 刷题集

在这里插入图片描述

试题 J: 括号序列

时间限制: 1.0s

内存限制: 256.0MB

本题总分:25 分

【问题描述】

给定一个括号序列,要求尽可能少地添加若干括号使得括号序列变得合法,

当添加完成后,会产生不同的添加结果,请问有多少种本质不同的添加结果。

两个结果是本质不同的是指存在某个位置一个结果是左括号,而另一个是右括

号。

例如,对于括号序列 (((),只需要添加两个括号就能让其合法,有以下几

种不同的添加结果:()()()、()(())、(())()、(()()) 和 ((()))。

【输入格式】

输入一行包含一个字符串 s,表示给定的括号序列,序列中只有左括号和

右括号。

【输出格式】

输出一个整数表示答案,答案可能很大,请输出答案除以 1000000007 (即

109 + 7) 的余数。

【样例输入】

((()

【样例输出】

5

【评测用例规模与约定】

对于 40% 的评测用例,|s| ≤ 200。

对于所有评测用例,1 ≤ |s| ≤ 5000。

image.png

package LanqiaobeiExam._12CB;

import java.util.Scanner;

/**
 * ClassName: J括号序列
 * Package: LanqiaobeiExam._12CB
 *
 * @DATE: 2022/3/22 21:36
 * Author: asleep
 */
public class J括号序列 {
    static int MOD = 1000000007;
    private static long calc(String s) {
        int n = s.length();
        long[][] dp = new long[n + 2][n + 2];   //+2  是因为dp状态转移方程需要  n+1的数(其实是懒得特判)
        char[] str = s.toCharArray();
        dp[0][0] = 1;
        for (int i = 1; i <= n; i++) {
            if (str[i - 1] == '(') {
                for (int j = 1; j <= n; j++) {
                    dp[i][j] = dp[i - 1][j - 1];
                }
            } else {
                dp[i][0] = (dp[i - 1][0] + dp[i - 1][1]) % MOD; //这一步用原状态转移式,新状态转移式子会越界
                for (int j = 1; j <= n; j++) {
                    dp[i][j] = (dp[i - 1][j + 1] + dp[i][j - 1]) % MOD;
                }
            }
        }
        for (int i = 0; i <= n; i++) {  //一定存在解,最差dp[n][n]也是解
            if (dp[n][i] > 0) { //  其实有一种可能是dp本来有值,但是 %MOD 后为0,显然测试用例没有这种情况(如果有这种情况加个boolean数组记录一下即可)
                return dp[n][i];
            }
        }
        return -1;
    }


    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.next();
        int n = s.length();
        long left = calc(s);
        char[] str = new StringBuilder(s).reverse().toString().toCharArray();
        for (int i = 0; i < n; i++) {
            if (str[i] == '(') {
                str[i] = ')';
            } else {
                str[i] = '(';
            }
        }
        String ss = new String(str);

        long right = calc(ss);
        System.out.println(left * right % MOD);
    }


}

#include <algorithm>
#include "iostream"
#include "cstring"

using namespace std;

const int N = 5010, MOD = 1e9 + 7;

int n;
char str[N];
int dp[N][N];

long calc() {
    memset(dp, 0, sizeof dp);
    dp[0][0] = 1;
    for (int i = 1; i <= n; i++) {
        if (str[i - 1] == '(') {
            for (int j = 1; j <= n; j++) {
                dp[i][j] = dp[i - 1][j - 1];
            }
        } else {
            dp[i][0] = (dp[i - 1][0] + dp[i - 1][1]) % MOD;
            for (int j = 1; j <= n; j++) {
                dp[i][j] = (dp[i - 1][j + 1] + dp[i][j - 1]) % MOD;
            }
        }
    }
    for (int i = 0; i <= n; i++) {
        if (dp[n][i]) {
            return dp[n][i];
        }
    }
    return -1;
}

int main() {
    cin >> str;
    n = strlen(str);
    long left = calc();
    int a = 10;
    reverse(str, str + n);
    for (int i = 0; i < n; i++) {
        if (str[i] == '(') {
            str[i] = ')';
        } else {
            str[i] = '(';
        }
    }
    long right = calc();
    cout << left * right % MOD << endl;
    return 0;
}