其他分享
首页 > 其他分享> > 第十二届蓝桥杯B组省赛括号序列题解

第十二届蓝桥杯B组省赛括号序列题解

作者:互联网

请添加图片描述

问题分析

首先要把括号序列的合法性表示出来

类似的,我们可以定义左括号合法性

右括号合法性

定义AL、AR、ANS

计算方法

对于如下序列,写出检查左括号合法性时C的变化过程

((( ) (( )
(((->123
)->122
((->12234
)->12233

C的数值其实是当前的空隙中最多可能插入的右括号数
所以在遇到右括号时就将该空隙的最大容量减一而不是添加一个新状态。
使左括号合法的过程就是在容量分别为12233的五个空隙中插入三个右括号。但要注意,还有其它约束,比如把三个括号都放到前两个空里就不合法。
这个约束就是:

我们把0到”C状态序列的长度“放在外层循环,当前在第几个空隙放到内层循环,F[n,c]表示将n个括号放到前c个空隙的方案数。
F的初始值如下(不管算到哪个空隙,插入0个括号的方案数一定是1)

  [0 1 2 3 4 5] ->第几个空隙
0  1 1 1 1 1 1
1  0 0 0 0 0 0
2  0 0 0 0 0 0
3  0 0 0 0 0 0
4  0 0 0 0 0 0
5  0 0 0 0 0 0
|
插入几个括号

对于((()
状态序列为122
F会成为

1 1 1 1
0 1 2 3
0 0 2 5

F[n,c]=F[n,c-1]+F[n-1.c-1]+F[n-2,c-1]…
当前项=当前空里插入0个括号+当前空里插入1个括号+当前空里插入2个…
=前c-1个空放n个括号+前c-1个空放n-1个括号…
约束条件是n<C[c]
最终我们要的结果在F[最后一个空隙的容量,空隙的总个数]

#include<bits/stdc++.h>
using namespace std;
#define NMAX 5000
#define VMA1 1000000007
int N,L;
int RES[NMAX+1];//C状态表(空隙状态表)
long long F[NMAX+1][NMAX+1];
string input ;
void init(){//检查合法性,生成空隙状态表
    L=0;
    for(int i=1;i<=N;++i){
        if(input[i-1]=='('){
            ++L;
            RES[L]=RES[L-1]+1;
        }else{
            if(RES[L]>0){
                RES[L]--;
            }
        }
    }
}
long long calc(){//计算使左括号合法的方案数
    memset(F,0,sizeof(F));
    //对所有的空隙一个括号也不插入的方案只有一种
    for(int c=0;c<=L;++c){
        F[0][c]=1;
    }
    //插入一个,两个...
    for(int n=1;n<=L;++n){
    	//第一个空、第二个空...
        for(int c=1;c<=L;++c){
        	//满足约束条件
            if(n<=RES[c]){
            	//当前放0个、1个...、放满或放n个
                /*for(int i=n;i>=0;--i){
                    F[n][c]+=F[i][c-1];
                    F[n][c]%=VMA1;//题目要求的防溢出
                }*/
                //F[n][c-1]就是当前放1个+当前放...
                F[n][c]=F[n-1][c]+F[n][c-1];
                F[n][c]%=VMA1;//题目要求的防溢出
            }
        }
    }
    return F[RES[L]][L];
}
int main(){
    cin >> input;
    N=input.size();
    init();//获取空隙状态表(左)
    long long v_left=calc();//计算使左括号合法方案数
    //括号种类反转
    for(int i=0;i<N;++i){
        input[i]=(input[i]=='('?')':'(');
    }
    //序列反转
    reverse(input.begin(),input.end());
    init();//获取空隙状态表(右)
    long long v_right=calc();//计算使右括号合法方案数
    cout << (v_left*v_right)%VMA1 << endl;//输出ANS
    return 0;
}

注:尽力写明白了,看不懂请参考 2021蓝桥杯省赛java组-J括号序列(满分题解).

标签:int,题解,long,蓝桥,括号,空隙,序列,input,组省赛
来源: https://blog.csdn.net/weixin_46216553/article/details/123073631