题解:P10992 [蓝桥杯 2023 国 Python A] 最长同类子串
Solution
「同类串」的定义为对于两个等长的字符串
直接进行字符串哈希很难做。注意到答案
从「同类串」的定义出发,所有字符出现位置相互对应和所有位置上的字符互相对应显然是等价的。
那我们不妨从字符出现的位置入手。
进一步地,两个为一组「同类串」的字符串里的所有字符上一次出现的位置一定相同。
故存下每一个位置上一个出现该位置上的字符的位置,判断两个字符串中是否存在长度固定的区间里所有字符上一次出现的位置相同。
使用哈希维护一个滑动窗口,每次滑动单位长度
故判断函数可以
Code
/* ChongYun */
#include<bits/stdc++.h>
#define START_LL 0
using namespace std;
#define start(x) using namespace x
#if START_LL
#define int long long
#endif
#define ull unsigned long long
namespace IO{
inline int read(){
register int x=0,f=1;
register char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar();
return x*f;
}
inline void write(int x){
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar((x%10)^48);
}
inline void write(int x,char ch){ write(x),putchar(ch); }
inline int read(string &Str){
char ch=getchar(); Str=" ";
while(ch<'a'||ch>'z') ch=getchar();
while(ch>='a'&&ch<='z') Str+=ch,ch=getchar();
return Str.size()-1;
}
inline void write(string Str){ register int i=0,__=Str.size(); while(i<__) putchar(Str[i]),++i; }
inline void write(string Str,char ch){ write(Str),putchar(ch); }
}start(IO);
const int N=1e5+5,Sigma=123;
int n,m,B;
string S,T;
ull base=1e5+3,pw[N],HashS[N],HashT[N];
int lstS[130],lstT[130],nowS[N],nowT[N],nxtS[N],nxtT[N];
unordered_map<ull,bool> vis;
void reHash(){ pw[0]=1; for(int i=1;i<=max(n,m);i++) pw[i]=pw[i-1]*base; }
bool check(int x){
vis.clear(); ull res=0;
for(int i=0;i<Sigma;++i) lstS[i]=lstT[i]=0;
for(int i=1;i<=n;++i) nxtS[i]=0,nowS[i]=B;
for(int i=1;i<=m;++i) nxtT[i]=0,nowT[i]=B;
for(int i=1;i<=n;++i){ if(lstS[S[i]]) nxtS[lstS[S[i]]]=i,nowS[i]=i-lstS[S[i]]; lstS[S[i]]=i; }
for(int i=1;i<=m;++i){ if(lstT[T[i]]) nxtT[lstT[T[i]]]=i,nowT[i]=i-lstT[T[i]]; lstT[T[i]]=i; }
for(int i=1;i<=x;++i) res=res*base+nowS[i];
vis[res]=1;
for(int i=2,len;i+x-1<=n;++i){
res=(res-nowS[i-1]*pw[x-1])*base+nowS[i+x-1];
if(nxtS[i-1]){
len=i+x-1-nxtS[i-1];
if(nxtS[i-1]<=n){
ull old=nowS[nxtS[i-1]]*pw[len];
nowS[nxtS[i-1]]=B;
if(nxtS[i-1]<=i+x-1) res-=old,res+=B*pw[len];
}
}
vis[res]=1;
}
res=0;
for(int i=1;i<=x;++i) res=res*base+nowT[i];
if(vis[res]) return 1;
for(int i=2,len;i+x-1<=m;++i){
res=(res-nowT[i-1]*pw[x-1])*base+nowT[i+x-1];
if(nxtT[i-1]){
len=i+x-1-nxtT[i-1];
if(nxtT[i-1]<=m){
ull old=nowT[nxtT[i-1]]*pw[len];
nowT[nxtT[i-1]]=B;
if(nxtT[i-1]<=i+x-1) res-=old,res+=B*pw[len];
}
}
if(vis.find(res)!=vis.end()) return 1;
}
return 0;
}
signed main(){
n=read(S),m=read(T);
reHash(),B=max(n,m)+1;
int l=1,r=min(n,m),mid,ans;
while(l<=r){
mid=(l+r)>>1;
if(check(mid)) l=mid+1,ans=mid;
else r=mid-1;
}
write(ans);
return 0;
}
2025.11.12 upd:突然翻到了这题,更新了一下实现。umap 显著提升了速度,虽然常数大但也比 map 快很多。时间复杂度