P4022 [CTSC2012]熟悉的文章 題解
阿新 • • 發佈:2022-05-18
對模式串建廣義SAM,對於每個匹配串,首先求出 \(sl_i\) 表示以 \(i\) 為結尾的字尾的最長匹配長度。設 \(dp_i\) 表示 \(1\sim i\) 的最長匹配長度和,二分答案 \(mid\) 之後,有如下 dp 方程:
\[dp_i=\max(dp_{i-1},\max_{i-sl_i\leq j\leq i-mid}dp_j+i-j) \]發現這個 \(i-sl_i\) 和 \(i-mid\) 都單調不減,所以可以直接單調佇列優化 dp,複雜度 \(O(|s|\log |s|)\)。
點選檢視程式碼
const int N=5e5+13; namespace ST{ const int logN=23; #define log2 _log2 int log2[N],f[N][logN]; inline void _init(int n){for(int i=2;i<=n;++i)log2[i]=log2[i>>1]+1;} inline void init(int n){ _init(n); int k=log2[n]+1; for(int j=1;j<=k;++j) for(int i=1;i+(1<<j)-1<=n;++i) f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]); } inline int query(int l,int r){int k=log2[r-l+1];return min(f[l][k],f[r-(1<<k)+1][k]);} #undef log2 } std::vector<int> a[N<<1]; #define P(i) a[(i)+N] int n,suf[N]; char s[N]; int nxt[N<<1],len[N<<1],ed[N<<1],ptot=1,lastpos=1,son[N<<1][2],zrzak[2]; inline int newpos(int nson[2],int nlen){return len[++ptot]=nlen,son[ptot][0]=nson[0],son[ptot][1]=nson[1],ptot;} inline void insert(int c,int pos){ int p=lastpos,u=newpos(zrzak,len[p]+1);ed[u]=pos; while(p&&!son[p][c]) son[p][c]=u,p=nxt[p]; lastpos=u; if(!p) return nxt[u]=1,void(); int d=son[p][c]; if(len[d]==len[p]+1) nxt[u]=d; else{ int v=newpos(son[d],len[p]+1);ed[v]=ed[d]; nxt[v]=nxt[d],nxt[d]=nxt[u]=v; while(p&&son[p][c]==d) son[p][c]=v,p=nxt[p]; } } inline bool check(int k,int pos){return ST::query(k,pos-1)>=suf[pos];} int main(){ read(n);read(s+1); for(int i=1;i<=n;++i) insert(s[i]=='(',i); for(int i=n;i;--i) suf[i]=suf[i+1]+(s[i]=='('?-1:1),ST::f[i][0]=suf[i]; for(int i=1;i<=n;++i) P(suf[i]).pb(i); ST::init(n);ll ans=0; for(int i=2;i<=ptot;++i){ int pos=ed[i]+1;int L=ed[i]-len[i]+1,R=ed[i]-len[nxt[i]]; int l=std::lower_bound(P(suf[pos]).begin(),P(suf[pos]).end(),L)-P(suf[pos]).begin(),r=std::upper_bound(P(suf[pos]).begin(),P(suf[pos]).end(),R)-P(suf[pos]).begin()-1; int tmp=r; if(l>r||!check(P(suf[pos])[r],pos)) continue; while(l<r){ int mid=(l+r)>>1; if(check(P(suf[pos])[mid],pos)) r=mid; else l=mid+1; } ans+=tmp-l+1; } println(ans); return 0; }