CF444D DZY Loves Strings 根號分治
阿新 • • 發佈:2020-12-01
題意:
分析:
巨佬說這題是根號分治裸題,我還是太菜了
- 暴力
對於每一個詢問,掃一遍原序列,求出 \(a\) 出現每一個位置,然後對於 \(b\) 一遍枚舉出現的位置,一邊雙指標找出離 \(b\) 最近的 \(a\) 出現的位置,複雜度 \(O(qn)\)
- 正解
我們發現,對於一個長為 \(n\) 的字串,裡面互不相同的長度小於 4 的子串只有 \(4n\) 個,其中出現次數大於 \(\sqrt{4n}\) 的串不超過 \(\sqrt{4n}\) 個
- 當 \(a,b\) 出現次數都小於 \(\sqrt{4n}\)
我們直接按照原來的雙指標列舉就行了,由於兩個串出現的次數都不超過 \(\sqrt{4n}\)
- 當 \(a,b\) 至少有一個出現次數大於 \(\sqrt{4n}\) 時
預處理它和每一個串的最小答案,由於這樣的串不超過 \(\sqrt{4n}\) 個,所以總的複雜度不超過 \(O(\sqrt{4n})\)
程式碼:
#include<bits/stdc++.h> #define pii pair<int,int> #define mk(x,y) make_pair(x,y) #define lc rt<<1 #define rc rt<<1|1 #define pb push_back #define fir first #define sec second using namespace std; namespace zzc { inline int read() { int x=0,f=1;char ch=getchar(); while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();} while (isdigit(ch)){x=x*10+ch-48;ch=getchar();} return x*f; } const int maxq = 5e5+5; const int maxn = 1e5+5; const int maxm = 5e5+5; const int blo = 400; char s[maxn],a[10],b[10]; int mp[maxq],f[blo][maxn],id[maxn][5],len[maxn],big[maxn]; int n,idx,cnt,qt; vector<int> pos[maxn]; int get(char *s,int l) { int res=0; for(int i=0;i<l;i++) res=res*26+(s[i]-96); return res; } void work() { scanf("%s",s+1);qt=read();n=strlen(s+1); for(int l=1;l<=4;l++) { for(int i=1,j=n-l+1;i<=j;i++) { int tmp=get(s+i,l); if(!mp[tmp]) mp[tmp]=++idx,len[idx]=l; pos[id[i][l]=mp[tmp]].pb(i); } } for(int i=1;i<=idx;i++)if(pos[i].size()>blo) { big[i]=++cnt; int sz=pos[i].size(),tmp=len[i]; memset(f[cnt],0x3f,sizeof(f[cnt])); for(int j=1;j<sz;j++) { int lef=pos[i][j-1]; int rig=pos[i][j]; for(int k=lef;k<rig;k++) for(int l=1;l<=4;l++) f[cnt][id[k][l]]=min(f[cnt][id[k][l]],min(max(k+l-lef,tmp),max(rig+tmp-k,l))); } for(int k=pos[i][sz-1],lef=pos[i][sz-1];k<=n;k++) for(int l=1;l<=4;l++) f[cnt][id[k][l]]=min(f[cnt][id[k][l]],max(k+l-lef,tmp)); for(int k=1,rig=pos[i][0];k<rig;k++) for(int l=1;l<=4;l++) f[cnt][id[k][l]]=min(f[cnt][id[k][l]],max(rig+tmp-k,l)); } while(qt--) { scanf("%s",a);scanf("%s",b); int x=mp[get(a,strlen(a))],y=mp[get(b,strlen(b))]; if(!x||!y) printf("-1\n"); else if(big[x]) printf("%d\n",f[big[x]][y]); else if(big[y]) printf("%d\n",f[big[y]][x]); else { int sz1=pos[x].size()-1,sz2=pos[y].size()-1,lx=len[x],ly=len[y],ans=0x3f3f3f3f,now=0; for(int i=0;i<=sz1;i++) { while(now<sz2&&pos[y][now]<pos[x][i]) now++; if(pos[y][now]>pos[x][i]) { ans=min(ans,pos[y][now]+ly-pos[x][i]); if(now) ans=min(ans,pos[x][i]+lx-pos[y][now-1]); } else ans=min(ans,pos[x][i]+lx-pos[y][now]); } printf("%d\n",max(ans,max(lx,ly))); } } } } int main() { zzc::work(); return 0; }