51Nod 1791 合法字串 棧+動歸
阿新 • • 發佈:2019-01-01
有一個括號序列,現在要計算一下它有多少非空子段是合法括號序列。
合法括號序列的定義是:
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; }