1. 程式人生 > >[分治] 51nod演算法馬拉松27 A.合法括號子段

[分治] 51nod演算法馬拉松27 A.合法括號子段

題意

有一個長度為 n 的括號序列,現在要計算一下它有多少非空子段是合法括號序列。
合法括號序列的定義是:
1.空序列是合法括號序列。
2.如果 S 是合法括號序列,那麼 (S) 是合法括號序列。
3.如果 AB 都是合法括號序列,那麼 AB 是合法括號序列。
n<=1100000

題解

A 題還是挺水的吧……
把左括號看 +1 ,右括號看成 1, 顯然一個串是合法括號序列的充要條件是:
所有字首和都大於等於 0 , 且整個的和剛好為 0.
然後我們就可以分治亂搞了,記一下各種資訊,推一下式子就好了。
不詳細講了……不然要寫一坨……
複雜度 O(nlogn)

#include<cstdio>
#include<cstring> #include<algorithm> using namespace std; typedef long long LL; const int maxn=1100005; char s[maxn]; int _test,n,sum[maxn],_min[maxn],_max[maxn],sum2[maxn],cnt[maxn*2]; LL ans; void Solve(int L,int R){ if(L>=R) return; int mid=(L+R)>>1; Solve(L,mid); Solve(mid+1
,R); _min[mid]=1e+9; sum[mid]=0; for(int i=mid+1;i<=R;i++){ sum[i]=sum[i-1]+(s[i]=='('?1:-1), _min[i]=min(_min[i-1],sum[i]); if(-_min[i]<=-sum[i]) cnt[-sum[i]+maxn]++; } sum2[mid+1]=_max[mid+1]=0; for(int i=mid;i>=L;i--){ sum2[i]=sum2[i+1]+(s[i]=='('
?1:-1); _max[i]=max(_max[i+1],sum2[i]); if(sum2[i]-_max[i+1]>=0) ans+=cnt[sum2[i]+maxn]; } for(int i=mid+1;i<=R;i++) if(-_min[i]<=-sum[i]) cnt[-sum[i]+maxn]--; } int main(){ scanf("%d",&_test); while(_test--){ scanf("%s",s+1); n=strlen(s+1); ans=0; Solve(1,n); printf("%lld\n",ans); } return 0; }