51Nod 1791 合法字符串 栈+动归

有一个括号序列,现在要计算一下它有多少非空子段是合法括号序列。
合法括号序列的定义是:
1.空序列是合法括号序列。
2.如果S是合法括号序列,那么(S)是合法括号序列。
3.如果A和B都是合法括号序列,那么AB是合法括号序列。
Input
多组测试数据。 
第一行有一个整数T(1<=T<=1100000),表示测试数据的数量。 
接下来T行,每一行都有一个括号序列,是一个由'('和')'组成的非空串。 
所有输入的括号序列的总长度不超过1100000。
Output
输出T行,每一行对应一个测试数据的答案。
Sample Input
5
(
()
()()
(()
(())
Sample Output
0
1
3
1
2
    
   拿到这道题比较棘手的原因来自于  如果A和B都是合法括号序列,那么AB是合法括号序列 这条规则,我们可以先不管这条规则,先处理符合前两条规则的,这就比较简单了,利用栈,我们是这样做的,用一个数组pos[i],初始化为-1,表示没有括号与之匹配,所以右括号的最终结果为-1,pos[a]=b;表示在a位置的这个左括号与b位置的有括号匹配,若pos[i]不等于-1.则在i位置的括号肯定为左括号。
   我们以上找出了所有的独立括号,接下来就用到了动态规划的思想了,ans[i]表示已i开头的括号有多少合法的括号序列 状态转移方程:
    ans[i] = ans[pos[i]+1] + 1   ( pos[i] != -1)
   在纸上写写就明白了,最后所有符合3条规则的合法括号序列为ans[0]+ans[1]+ans[2]+......+ans[n-1];
    分治也可以做这道题,不过我没看多懂
    
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h> 
#include <string>
#include <vector>
#include <queue> 
#include <stack> 
#include <set>
#include <map>
using namespace std;
typedef long long ll;
const int MAXN=1100005;
stack <int> s;
ll dp[MAXN];
int pos[MAXN];
char ss[MAXN];
int main(void)
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		while(!s.empty()) s.pop();
		scanf("%s",ss);
		int len=strlen(ss);
		for(int i=0;i<=len+1;i++)
		{
			pos[i]=-1;
			dp[i]=0;
		}
		for(int i=0;i<len;i++)
		{
			if(ss[i]=='(') s.push(i);
			else{
				if(s.empty()) continue;
				pos[s.top()]=i;
				s.pop();
			}
		}
		ll ans=0;
		for(int i=len-1;i>=0;i--)
		{
			if(pos[i]==-1) continue;
			dp[i]=dp[pos[i]+1]+1;
			ans+=dp[i];
		}
		printf("%lld\n",ans);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值