codeforces 5C

C. Longest Regular Bracket Sequence
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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

(吐槽:这题真是道好题呀。。想贪心贪心不出来,想dp,转移方程不知从何推起。。。

题意:给一个字符串,有左括号和右括号。求满足括号配对的最长子串的长度及个数。

解题思路1:求dp转移方程。遇到左括号就记录下来,遇到右括号,就把与之最近的左括号取出来(如果有的话)与右括号配对,此时这段的长度是右括号位置与左括号位置之差,记为dp[t]。
此时的这个长度,再加上一个相邻串的长度即dp[t-1]的长度,就是目前这个串的长度啦,所以转移方程就是dp[t]=dp[t-1]+i-t+1;
附ac代码:
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <stack>
 6 using namespace std;
 7 const int maxn = 1e6+5;
 8 int dp[maxn];
 9 stack<int>q;
10 int main() {
11     ios::sync_with_stdio(false);
12     cin.tie(0);cout.tie(0);
13     string s;
14     int cnt=1,maxx=0;
15     cin>>s;
16     for(int i=0;i<s.size();++i) {
17          if(s[i]=='(') {
18              q.push(i);
19          }
20          else if(!q.empty()) {
21              int u=q.top();
22              q.pop();
23              dp[i]=dp[u-1]+i-u+1;
24              if(dp[i]>maxx) {
25                  maxx=dp[i];
26                  cnt=1;
27              }
28              else if(dp[i]==maxx) {
29                  cnt++;
30              }
31          }
32     }
33     if(maxx==0) cout<<0<<" "<<1;
34     else cout<<maxx<<" "<<cnt;
35     return  0;
36 }
View Code

 

解题思路2:先找出能够括号匹配的子串,然后判断哪个最长。具体做法是分别从前向后和从后向前遍历一遍,比如从前向后遍历的时候,遇到一个右括号且左括号不为0的时候,说明这个右括号是肯定可以括号匹配的,记录下来dp[i]=1,反向遍历也是同样操作。

然后for循环遍历记录数组,看dp[i]是否为1,找出最长的及其个数,代码比文字更好理解。

附ac代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <stack>
 6 using namespace std;
 7 const int maxn = 1e6+5;
 8 int dp[maxn];
 9 stack<int>q;
10 int main() {
11     ios::sync_with_stdio(false);
12     cin.tie(0);cout.tie(0);
13     string s;
14     int cnt=0,maxx=0,ans=0;
15     cin>>s;
16     for(int i=0;i<s.size();++i) {
17         if(s[i]=='(') {
18             ++cnt;
19         }
20         else if(cnt>0) {
21             dp[i]=1;
22             --cnt;
23         }
24     }
25     cnt=0;
26     for(int i=s.size()-1;i>=0;--i) {
27         if(s[i]==')') {
28             ++cnt;
29         }
30         else if(cnt>0) {
31             dp[i]=1;
32             --cnt;
33         }
34     }
35     cnt=1;ans=1;
36     for(int i=0;i<s.size();++i) {
37         if(dp[i]&&dp[i+1]) {
38             ++cnt;
39         }
40         else cnt=1;
41         if(cnt>maxx) {
42             maxx=cnt;
43             ans=0;
44         }
45         if(cnt==maxx) {
46             ++ans;
47         }
48     }
49     if(maxx==1) cout<<0<<" "<<1;
50     else cout<<maxx<<" "<<ans;
51     return  0;
52 }
View Code

 

 

posted @ 2017-10-19 23:28  euzmin  阅读(285)  评论(0编辑  收藏  举报