Leetcode <622.設計迴圈佇列>
阿新 • • 發佈:2020-12-23
一、題目
二、解法
今天不知道為什麼手感這麼好,寫一發完全沒調就過掉了。
我感覺這種多組詢問的字串題是很難的,經常沒有什麼思路。我先考慮了一下能不能像 區間本質不同的子串個數 這樣直接離線,但我想了很久發現不行的。
正確的做法是很天馬行空的,我們 考慮預處理出 \(s\) 的所有子串在 \(t\) 中有沒有出現 ,列舉是不可能列舉的,要把他們壓在一起快速的處理。設 \(R[i]\) 為 \([i,R[i]]\) 在 \(t\) 中出現過,那麼對於比 \(R[i]\) 小的右端點是一定出現過的,比 \(R[i]\) 大的右端點是沒有出現過的。
\(R[i]\) 用字尾自動機可以快速處理,因為 \([i,R[i]]\)
知道了 \(R[i]\) 之後,詢問 \((l,r)\) 的答案很容易寫出來:
\[\max_{i=l}^r (\min(R[i],r)-i+1) \]這個式子乍看上去沒有辦法優化,但別忘了我們還有一個法寶:離線 。如果你覺得裡面的 \(\min\) 特別噁心那麼我們可以分類討論來去掉這個 \(\min\) :
- \(R[i]\leq r\)
- \(R[i]>r\),那麼裡面的柿子就變成了:\(r-i+1\)
拆掉 \(\min\) 之後問題變成了二維偏序之類的東西,解決他的固定套路就是 排序降維 。那麼我們把 \(R[i],r\) 都從小到大排序,然後維護兩顆線段樹,一顆維護 \(-i\) 的最大值,一顆維護 \(R[i]-i+1\) 就可以了。
時間複雜度 \(O(n\log n)\)
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int M = 200005; const int inf = -1e9; int read() { int x=0,f=1;char c; while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;} while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();} return x*f; } int n,m,k,cnt,last,R[M],ans[M];char s[M],t[M]; int mx[2][4*M]; struct node { int fa,len,ch[2]; }a[2*M]; struct reg//regret { int l,r,id; bool operator < (const reg &R) const { return r<R.r; } }b[M],q[M]; void add(int c) { int p=last,np=last=++cnt; a[np].len=a[p].len; for(;p && !a[p].ch[c];p=a[p].fa) a[p].ch[c]=np; if(!p) a[np].fa=1; else { int q=a[p].ch[c]; if(a[p].len+1==a[q].len) a[np].fa=q; else { int nq=++cnt;a[nq]=a[q]; a[nq].len=a[p].len+1; a[np].fa=a[q].fa=nq; for(;p && a[p].ch[c]==q;p=a[p].fa) a[p].ch[c]=nq; } } } void ins(int i,int l,int r,int id,int v,int f) { if(l==r) { mx[f][i]=v; return ; } int mid=(l+r)>>1; if(mid>=id) ins(i<<1,l,mid,id,v,f); else ins(i<<1|1,mid+1,r,id,v,f); mx[f][i]=max(mx[f][i<<1],mx[f][i<<1|1]); } int ask(int i,int l,int r,int L,int R,int f) { if(L>r || l>R) return inf; if(L<=l && r<=R) return mx[f][i]; int mid=(l+r)>>1; return max(ask(i<<1,l,mid,L,R,f),ask(i<<1|1,mid+1,r,L,R,f)); } signed main() { scanf("%s %s",s+1,t+1); n=strlen(s+1);m=strlen(t+1); cnt=last=1;//attention for(int i=1;i<=m;i++) add(t[i]-'a'); for(int i=1,p=1;i<=n;i++) { int r=min(i-1,R[i-1]); if(r==i-1) p=1; while(p!=1 && a[a[p].fa].len>r-i+1) p=a[p].fa; while(r<n && a[p].ch[s[r+1]-'a']) { r++; p=a[p].ch[s[r]-'a']; } R[i]=r; b[i]=reg{i,r,0}; } sort(b+1,b+1+n); k=read(); for(int i=1;i<=k;i++) { int l=read(),r=read(); q[i]=reg{l,r,i}; } sort(q+1,q+1+k); memset(mx,-0x3f,sizeof mx); for(int i=1;i<=n;i++) ins(1,1,n,i,-i,0); for(int i=1,j=1;i<=k;i++) { int l=q[i].l,r=q[i].r,id=q[i].id; while(j<=n && b[j].r<=r) { ins(1,1,n,b[j].l,inf,0); ins(1,1,n,b[j].l,b[j].r-b[j].l+1,1); j++; } ans[id]=max(ask(1,1,n,l,r,1),r+ask(1,1,n,l,r,0)+1); ans[id]=max(0,ans[id]); } for(int i=1;i<=k;i++) printf("%d\n",ans[i]); }