似乎还没有靠谱的题解嘛。。。我来写一发。
首先我们发现,每个询问都很短,最长只有四。27^4=531441,所以显然可以把这个字符串hash一下,把出现的所有位置存下来,直接丢到vector里。由于是从头到尾扫一遍,所以vector里面的元素已经是有序的了。
然后我们发现有这样一个特点:如果询问的两个字符串出现次数都不超过根号|S|,我们可以直接利用单调性扫过去,枚举A的出现位置,每次找到离它最近的B中的位置,这个可以用A出现次数+B出现次数次计算完成,所以总的复杂度是O(根号N*Q)
其他的情况下,由于出现次数超过根号N的字符串最多只有根号N个,我们可以。。。
可以什么啊!完全不懂啊!
并不是这样做的(雾)
其实,我们把相同的询问放到map里存着,其他的直接和一开始的一样处理就好了。
复杂度我也不太会证= =反正能跑过就行了。。。
附代码
#include<bits/stdc++.h>
#define N 50100
using namespace std;
char sss[N],a[5],b[5];
vector<int> cx[531442];
int len;
inline int gethas(char *c){
int tot=0;
for(int i=0;i<strlen(c);i++) tot=tot*27+c[i]-'a'+1;
return tot;
}
inline void check_min(int &a,int b){if(b<a) a=b;}
map<long long,int> s;
long long base=27*27*27*27;
int main(){
scanf("%s",sss);len=strlen(sss);
for(int i=0;i<len;i++){
int has=0;
for(int j=0;j+i<len&&j<4;j++){
has=has*27+sss[i+j]-'a'+1;
cx[has].push_back(i);
}
}
int q;scanf("%d",&q);
while(q--){
scanf("%s%s",a,b);
int hasa=gethas(a),hasb=gethas(b);
int ll=strlen(a),rr=strlen(b);
if(hasa>hasb) swap(hasa,hasb),swap(ll,rr);
int l=cx[hasa].size(),r=cx[hasb].size();
int ans=1000086;
if(l==0||r==0) puts("-1");
else{
if(s[hasa*base+hasb]){
printf("%d\n",s[hasa*base+hasb]);
continue;
}
for(int i=0,now=0;i<l;i++){
while(cx[hasb][now]<cx[hasa][i]&&now<r) now++;
if(now!=r) ans=min(ans,(int)max(cx[hasb][now]+rr,cx[hasa][i]+ll)-cx[hasa][i]);
if(now!=0) ans=min(ans,(int)max(cx[hasb][now-1]+rr,cx[hasa][i]+ll)-cx[hasb][now-1]);
}
printf("%d\n",s[hasa*base+hasb]=ans);
}
}
return 0;
}