二分加hash,这里用map记录的操作非常秀,从两个循环优化成一个for,很细节
#include<bits/stdc++.h>
using namespace std;
using ull = unsigned long long;
const ull base = 233;
int main(){
string s;cin>>s;
int n;
n = (int)s.size();
vector<ull> pw(n+1),has(n+1);
pw[0]=1;
for(int i=1;i<=n;i++)pw[i] = pw[i-1]*base;
for(int i=1;i<=n;i++)has[i] = has[i-1]*base + s[i-1];
auto get = [&](int l,int r){
//pw是r-l别老是写反了
return has[r]-has[l]*pw[r-l];
};
//可以发现此题具有二分性
int l=0,r=n/2,ret=0;
while(l<=r){
int mid = (l+r)>>1;
int fl = 0;
//这个操作很秀
map<ull,int> M; //map记录的是最早出现的右端点的hash值
//这样可以用一个循环搞定
for(int i=0;i + mid<=n;i++){
int j = i + mid;//j为右端点
ull h =get(i,j);
//这句话语法为有没有这个元素
//这里面很细节
if(M.count(h)) {
int p = M[h];
if(i>p) {
fl = 1;
break;
}
}else{
M[h] = j;
}
}
if(fl)ret = mid,l=mid+1;
else r = mid - 1;
}
cout << ret <<endl;
return 0;
}