Longest Regular Bracket Sequence CodeForces - 5C(区间DP)

碎碎念

这道题着实想了好久啊,自己做是不行了。看了大神的题解,就没有详细解释的,标着水题的人是有多可怕,最后只能按照计算机的执行步骤一步步演示才弄懂的。

区间DP之前就会做石子合并的模板题,今天也算是又学会一种,距离我能理解这DP大概还有很长一段路要走。

思路

石子合并那种题,就是最最模板的那种 :一次决策后就可以将一个大区间分成两个小区间,先解决小区间的问题再把小区间合并

对于这个题来说,我怎么看都不是很明显的模板啊,难道是又一类题型??

感觉这个题也没有将一个大区间分成小区间,再继续划分啊,就是从左向右跑一边整个串,比较DP的可能就是当前状态值由之前的状态值推出来吧

区间DP的状态选择:很多都是将下标位置作为一个状态的变量

状态选择:这个题也是,状态dp[i]是以i位置的右括号结尾的合法子串的长度 (也就是若i位置是左括号或者不合法的右括号,其状态值dp[i] = 0,这个在dp初始化的时候就会实现,只要后面在这两种情况下不对其进行操作,dp[i]就是0的)

状态转移方程:dp[i] = dp[temp-1]+i-temp+1;   (temp是i对应的左括号位置)

括号合法的情况就是两种:一个是s合法则(s)合法,这种状态转移要靠最右的右括号位置减去其匹配的左括号位置+1; 还有一中就是s,t合法,则st合法,这种状态转移靠加上dp [ s的右括号的dp值(也就是t左括号-1的位置的dp值)]

这两种情况都得加上 dp[i] = dp[temp-1]+i-temp+1;  若temp左边是左括号则可能匹配的情况只能是(s),或者多余的不合法括号,留到后面遇到对应的右括号再算 。若是右括号则可能是不匹配或者st,这个根据dp [ t 的右括号 ] ,直接就算出来了。

还有就是这个栈的使用,感觉也不算是作为区间DP的右边界吧,就是为了dp[i]判断当是右括号时是否合法用的,而且栈的好处是肯定给这个右括号匹配的是挨着它最近的那个左括号,这样就完全符合了判断括号是否合法的方法。


Description

This is yet another problem dealing with regular bracket sequences.

We should remind you that a bracket sequence is called regular, if by inserting «+» and «1» into it we can get a correct mathematical expression. For example, sequences «(())()», «()» and «(()(()))» are regular, while «)(», «(()» and «(()))(» are not.

You are given a string of «(» and «)» characters. You are to find its longest substring that is a regular bracket sequence. You are to find the number of such substrings as well.

Input

The first line of the input file contains a non-empty string, consisting of «(» and «)» characters. Its length does not exceed 106.

Output

Print the length of the longest substring that is a regular bracket sequence, and the number of such substrings. If there are no such substrings, write the only line containing "0 1".

Examples

Input

)((())))(()())

Output

6 2

Input

))(

Output

0 1


代码

#include<cstdio>
#include<stack>
#include<cstring> 
using namespace std;
int dp[1000005]; 
char a[1000005];
stack<int> s;
int main(void)
{
	while(scanf("%s",a)!=EOF)
	{
		while(!s.empty()) s.pop();
		int n = strlen(a);
		memset(dp,0,sizeof(dp));//初始化边界值,因为除了需要计算的情况,其余值应均为0 
		int max = 0,count = 0;
		for(int i = 0;i<n;i++)//跑一边整个串 
		{
			if(a[i]=='(')
				s.push(i);
			else if(a[i]==')'&&!s.empty())//若是右括号并且有可以匹配的左括号的话是合法的子串了 
			{
				int temp = s.top();//先弹出与之匹配的左括号 
				s.pop();
				dp[i] = dp[temp-1]+i-temp+1; 
				if(dp[i]>max)
				{
					count = 1;
					max = dp[i];
				}	
				else if(dp[i]==max)
					count++;
			}										
		} 
		if(max==0) printf("0 1\n");
		else printf("%d %d\n",max,count);		
	}		
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39352598/article/details/81414167