1. 程式人生 > >51Nod 1791 合法字串 棧+動歸

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;
}