1. 程式人生 > >【AUOJ1588】括號序列

【AUOJ1588】括號序列

題面

溫神不喜歡括號序列,但是他發現總是有人喜歡出括號序列的題。

為了讓全世界都能感受到他的痛苦,他想要寫一個轉換器:它能把普通的小寫字串轉換成長度相同的合法的括號序列。

在溫神的構思中,這樣的轉換器需要滿足如下兩個條件:

  1. 結果的括號序列必須要是合法的,即左右括號必須要是相匹配的。
  2. 對於一對相匹配的左右括號,他們所在的位置原來的小寫字母必須相同。

舉例來說,對於字串 aabaab()(()) 就是一個合法的答案,而 ()()() 不滿足第二個條件,(((())不滿足第一個條件。

溫神發現,不是對於所有的小寫字串,都存在滿足條件的轉化方案。於是她給出了一個字串 s,她想要知道有多少個區間 [l,r],滿足區間 [l,r] 形成的字串存在每組條件的轉化方案。

對於 20% 的資料,|s|≤20。  對於 40% 的資料,|s|≤500。  對於 70% 的資料,|s|≤5000。  對於 100% 的資料,|s|≤1e6。

分析

dp或者最簡單的用棧模擬,都可以搞70分

然而正解是字串雜湊,我們可以觀察發現,當[1,i]的棧內序列等於[1,j]的棧內序列的時候,說明[i+1,j]是合法的,同理如果[1,k]也等於[1,i]時的,那麼[k,j]的區間也是合法的。

所以用雙雜湊存一下,Map對映一下記錄出現次數

程式碼

 

#include<bits/stdc++.h>
using namespace
std; #define N 1000010 typedef long long ll; char s[N],sta[N]; ll top=0,hash1,hash2,p1=131,p2=13331,len; ll pow1[N],pow2[N]; map<ll,ll>mp; int mod=1000007; int main() { scanf("%s",s+1); len=strlen(s+1); long long ans=0; pow1[0]=1,pow2[0]=1; for (long long i=1;i<=len;i++) pow1[i]=pow1[i-1
]*p1%mod,pow2[i]=pow2[i-1]*p2%mod; mp[0]=1; for (long long i=1;i<=len;i++) { if(!top||sta[top]!=s[i]) { sta[++top]=s[i]; hash1+=pow1[top]*(s[i]-'a'+1)%mod;hash1%=mod; hash2+=pow2[top]*(s[i]-'a'+1)%mod;hash2%=mod; } else { hash1+=mod-pow1[top]*(s[i]-'a'+1)%mod;hash1%=mod; hash2+=mod-pow2[top]*(s[i]-'a'+1)%mod;hash2%=mod; top--; } ans+=mp[hash1*mod+hash2]; mp[hash1*mod+hash2]++; } printf("%lld\n",ans); }