题意:给你一个串由"(",")","-"三个命令组成,( 代表加一个左括号,) 代表加一个右括号,- 代表删除前一个添加的括号,定义平衡串:
- “()”
- “(X)” 当X 是一个平衡串
- “XY”当X和Y都是一个平衡串
问你每输入一个命令后,字符串中包含多少个平衡串。
样例:
样例一 (()())---) 0 0 1 1 3 4 3 1 1 2 样例二 ()--()()----)(()())) 0 1 0 0 0 1 1 3 1 1 0 0 0 0 0 1 1 3 4 4
思路:首先要用栈来找出互相配对的括号,这个比较简单,难的是如何找到一个串所有的平衡串(一看这个题就往dp上想)。
定义dp[i]:代表以第i个字符结尾的字符串有多少个平衡串。当前结尾的字符是‘)’,dp的转移方程为dp[i]=dp[st.top()-1]+1,st.top代表和)配对的左括号的下标,具体见代码。
#include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<cstdio> #include<vector> #include<map> #include<set> #include<queue> #include<stack> //#define _for(i,a,b) for(int i=a;i<=b;i++) using namespace std; typedef long long ll; double eps=0.05; ll mod=1e15+7; const int INF =0x3f3f3f; const int MAXN=2e3+10; const int maxn = 1e5+10; //ll inf=100000000000000; //template<typename T>inline void read(T &x) //{ // x=0; // static int p;p=1; // static char c;c=getchar(); // while(!isdigit(c)){if(c=='-')p=-1;c=getchar();} // while(isdigit(c)) {x=(x<<1)+(x<<3)+(c-48);c=getchar();} // x*=p; //} typedef unsigned long long ull; const int N=2e5+7; stack<int> st; char s[200010]; ll dp[200010]; int match[2000010]; int main() { scanf("%s",s+1); int len=strlen(s+1); int cnt=0; ll ans=0; for(int i=1;i<=len;i++){ if(s[i]=='('){ cnt++; dp[cnt]=0; match[cnt]=0; st.push(cnt); } else if(s[i]==')'){ cnt++; if(!st.empty()){ match[cnt]=st.top(); dp[cnt]=dp[st.top()-1]+1; st.pop(); } else { match[cnt]=0; dp[cnt]=0; } ans+=dp[cnt]; } else if(s[i]=='-'){ ans-=dp[cnt]; while(!st.empty()&&st.top()>=cnt) st.pop(); if(match[cnt]!=0) st.push(match[cnt]); cnt--; } printf("%lld\n",ans); } }