您的位置:首页 > 其它

51 Nod 1791 合法括号子段【分治+字符串】

2017-08-02 16:00 363 查看
1791 合法括号子段


基准时间限制:1 秒 空间限制:131072 KB 分值: 40
难度:4级算法题

有一个括号序列,现在要计算一下它有多少非空子段是合法括号序列。

合法括号序列的定义是:

1.空序列是合法括号序列。

2.如果S是合法括号序列,那么(S)是合法括号序列。
3.如果A和B都是合法括号序列,那么AB是合法括号序列。

Input
多组测试数据。
第一行有一个整数T(1<=T<=1100000),表示测试数据的数量。
接下来T行,每一行都有一个括号序列,是一个由'('和')'组成的非空串。
所有输入的括号序列的总长度不超过1100000。

Output
输出T行,每一行对应一个测试数据的答案。

Input示例
5
(
()
()()
(()
(())

Output示例
0
1
3
1
2


题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1791
分析:
这里,我们需要明确区分一个定义,什么叫做子段?什么叫做子序列?子段是子序列的一种,也叫做连续子序列,而子序列呢?如果不要求连续,则是可以从原序列中任意取,但是要保持原先的先后顺序即可。

一个简单的分治,分别控制子段的左右两端点在左右两个区间内,然后从中间开始查找,控制左右两个半区间的合法性即可。

下面给出AC代码:

#include <stdio.h>
#include <cstring>
#include <iostream>
#include <string>
#include <algorithm>
#include <stack>
using namespace std;
typedef long long ll;
const int maxn = 1100005;
int dp[maxn];
char s[maxn];
int main (void)
{
ios::sync_with_stdio(false);
int n;
scanf("%d",&n);
for(int k=1;k<=n;++k)
{
scanf("%s",s);
stack<int>st;
int len=strlen(s);
for(int i=0;i<len;++i)
{
if(s[i]==')')
{
if(st.empty())
continue;
int tmp=st.top();
st.pop();
if(tmp!=0)
dp[i]=dp[tmp-1]+1;
else
dp[i]=1;
}
else
st.push(i);
}
ll ans=0;
for(int i=0;i<len;++i)
{
ans+=dp[i];
dp[i]=0;
}
printf("%lld\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: