最长的合法序列(栈+dp)
B. 最长合法括号序列 [ Problem 4472 ] [ Discussion ]
Description
这是另一道处理合法括号序列的题目。
我们应该提醒你,如果一个括号序列插入“+”和“1”后,可以得到一个正确的数学表达式,那么它被称为“合法”的。例如,序列“(())()”,“()”和“(()(()))”是合法的,但“)(”,“(()”和“(()))(”不是。
给出一个由“(”和“)”字符组成的字符串。你要找出它最长的是合法括号序列的子串,也同样要找出最长子串的个数。
Input
一行包含一个非空字符串,由“(”和“)”字符组成,长度不超过106106。
Output
输出最长合法括号序列的子串的长度,和最长子串的个数。
如果不存在这种子串,输出唯一的一行,包含“0 1”。
Samples
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; } }