題面
英文題面
題意:給定一個長度爲\(n\)的括號串,問有多少種不一樣的合法括號子串。
\(n \leq 5\times 10^5\)
題解:
先考慮暴力的作法:枚舉左端點,而後每次掃一遍,有括號平衡就將其加入答案,再用哈希+map判一下重。
再考慮不須要去重時的快速作法。
令\(s_i\)表示前\(i\)個字符,左括號個數與右括號個數的差。發現當固定左端點\(l\)時,合法的右端點\(r\)須要知足:
1.\(s_l = s_r\)
2.\(\forall_{i=l}^{r} , s_i \geq s_l\)
因此咱們開一個樹狀數組記一下權值,枚舉左端點,二分出知足第二個限制的最大的\(r\),在樹狀數組上查詢便可。
二分的check能夠用rmq作到O(1)查詢。
那麼如何去重呢?考慮後綴數組的height數組的意義,不難發現對於每一個\(l\),答案只須要減去\(r\)在\([l,l+height_{rank_l}-1]\)這段的貢獻便可。
時間複雜度:\(O(nlogn)\)
代碼:ios
#include<bits/stdc++.h> using namespace std; #define re register int #define F(x,y,z) for(re x=y;x<=z;x++) #define FOR(x,y,z) for(re x=y;x>=z;x--) typedef long long ll; #define I inline void #define IN inline int char c[505000]; int n,m,buc[505000],sa[505000],tot,rk[505000],tp[505000],hei[505000]; int s[505000],f[505000][22],lg[505000]; vector<int>st[1010000]; ll ans; I build_sa(){ m=2; F(i,1,n)buc[rk[i]=(c[i]=='('?1:2)]++; F(i,1,m)buc[i]+=buc[i-1]; FOR(i,n,1)sa[buc[rk[i]]--]=i; for(re k=1;k<=n;k<<=1){ tot=0; F(i,n-k+1,n)tp[++tot]=i; F(i,1,n)if(sa[i]>k)tp[++tot]=sa[i]-k; F(i,1,m)buc[i]=0; F(i,1,n)buc[rk[i]]++; F(i,1,m)buc[i]+=buc[i-1]; FOR(i,n,1)sa[buc[rk[tp[i]]]--]=tp[i],tp[i]=0; swap(rk,tp); rk[sa[1]]=tot=1; F(i,2,n)rk[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+k]==tp[sa[i]+k])?tot:++tot; if(tot==n)break; m=tot; } re k=0; F(i,1,n){ if(rk[i]==1)continue; if(k)k--; re p=sa[rk[i]-1]; while(c[i+k]==c[p+k])k++; hei[rk[i]]=k; } // F(i,1,n)cout<<sa[i]<<" ";cout<<endl; // F(i,1,n)cout<<rk[i]<<" ";cout<<endl; // F(i,1,n)cout<<hei[i]<<" ";cout<<endl; } I build_rmq(){ F(i,1,n)s[i]=s[i-1]+(c[i]=='('?1:-1); F(i,0,n<<1)st[i].emplace_back(0); F(i,1,n)s[i]+=n,st[s[i]].emplace_back(i);s[0]=n; lg[0]=-1;F(i,1,n)lg[i]=lg[i>>1]+1,f[i][0]=s[i]; F(j,1,lg[n])F(i,1,n-(1<<j)+1)f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]); } IN ques_min(int l,int r){ re len=lg[r-l+1]; return min(f[l][len],f[r-(1<<len)+1][len]); } IN ques(int l,int r){ if(l>=r||c[l]==')')return 0; re x=l,y=r,mid,w=s[l-1],res; while(x!=y){ mid=(x+y+1)>>1; if(ques_min(l,mid)>=w)x=mid; else y=mid-1; // cout<<x<<" "<<y<<endl; } // cout<<w<<":"; // for(auto d:st[w])cout<<d<<" ";cout<<endl; res=(upper_bound(st[w].begin(),st[w].end(),x)-st[w].begin())-(upper_bound(st[w].begin(),st[w].end(),l-1)-st[w].begin()); // cout<<"!"<<l<<" "<<r<<" "<<x<<" "<<w<<" "<<upper_bound(st[w].begin(),st[w].end(),x)-st[w].begin()<<" "<<res<<endl; return res; } int main(){ ios::sync_with_stdio(false);cin.tie(0); cin>>n>>c+1; build_sa();build_rmq(); // while(1){ // int l,r;cin>>l>>r;cout<<ques_min(l,r)<<endl; // } F(i,1,n)ans+=ques(sa[i],n)-ques(sa[i],sa[i]+hei[i]-1); cout<<ans; return 0; }