最长的合法序列(栈+dp)

B. 最长合法括号序列 Problem 4472  ] Discussion ]


Description

这是另一道处理合法括号序列的题目。
我们应该提醒你,如果一个括号序列插入“+”和“1”后,可以得到一个正确的数学表达式,那么它被称为“合法”的。例如,序列“(())()”,“()”和“(()(()))”是合法的,但“)(”,“(()”和“(()))(”不是。
给出一个由“(”和“)”字符组成的字符串。你要找出它最长的是合法括号序列的子串,也同样要找出最长子串的个数。

Input

一行包含一个非空字符串,由“(”和“)”字符组成,长度不超过106106。

Output

输出最长合法括号序列的子串的长度,和最长子串的个数。
如果不存在这种子串,输出唯一的一行,包含“0 1”。

Samples

Input Copy
)((())))(()())
Output
6 2
Input Copy
))(
Output
0 1

Hint

  • 对于50%的数据满足:读入的字符串长度小于等于1000;
  • 对于100%的数据满足:读入的字符串长度小于等于1000000。

这个题要用栈来维护括号进入顺序

这个题就是要用dp记录位置i上的最长合法长度,把左括号压进去,右括号会跟栈顶的左括号匹配,然后这个左括号会跟它位置-1的合法括号序列拼起来

至于这个为什么要加权值i-s.top()+1;

( )

( ( ) ( ) )
( ( ) )

同过这第二个例子你就看出来了.

其实通过这个例子可以帮助你来理解就是  ( ) ( ( ) ( ) ),f序列为0,2,0,0,2,0,4,8,

主要是f[8]=f[2]+8-3+1=8;

就是这样

  

 

#include<iostream>
#include<algorithm>
#include<stack> 
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=2e6+100;
char a[maxn];
stack<int>s;
int f[maxn];
/*
()
()()
(())

结合这三种就可以看出权值为i-s.top()+1 
*/
int len,ma=0;
void inint(){
    scanf("%s",a+1);
    len=strlen(a+1);
} 
void solve(){
    for(int i=1;i<=len;i++){
        if(a[i]=='('){
            s.push(i);
        }        
        else if(!s.empty()){
            f[i]=f[s.top()-1]+i-s.top()+1;
            ma=max(ma,f[i]);
            s.pop();
        } 
    }
} 
int main(){
    inint(); 
    ma=0;
    solve();
    int cnt=0;
    for(int i=1;i<=len;i++){
        if(f[i]==ma){
            cnt++;
        }
    }
    if(ma==0){
        cout<<0<<" "<<1<<endl;
    }
    else{
        cout<<ma<<" "<<cnt<<endl;
    }
} 

 

 

 

posted @ 2021-01-21 15:11  lipu123  阅读(145)  评论(0编辑  收藏  举报