题意:
分析:
巨佬说这题是根号分治裸题,我还是太菜了
- 暴力
对于每一个询问,扫一遍原序列,求出 (a) 出现每一个位置,然后对于 (b) 一遍枚举出现的位置,一边双指针找出离 (b) 最近的 (a) 出现的位置,复杂度 (O(qn))
- 正解
我们发现,对于一个长为 (n) 的字符串,里面互不相同的长度小于 4 的子串只有 (4n) 个,其中出现次数大于 (sqrt{4n}) 的串不超过 (sqrt{4n}) 个
- 当 (a,b) 出现次数都小于 (sqrt{4n})
我们直接按照原来的双指针枚举就行了,由于两个串出现的次数都不超过 (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
");
else if(big[x]) printf("%d
",f[big[x]][y]);
else if(big[y]) printf("%d
",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
",max(ans,max(lx,ly)));
}
}
}
}
int main()
{
zzc::work();
return 0;
}