http://acm.dlut.edu.cn/problem.php?id=1251
先把两个串的hash值都求出来,然后用二分答案的方法枚举子串的长度,把一个串的所有该长度的子串的hash值放进hashtable里面,用另一个串的该长度的子串的hash值去hashtable里查找有没有。如果找到了答案就去找更长长度的子串,否则找更短长度的。
二分确实很好用,如果有单调性的话尽量考虑使用,可以把n的复杂度简化为logn。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef unsigned long long ll;
const int maxn=100005;
const int mod=100007;
const int base=131;
char a[maxn],b[maxn];
ll H[maxn],xp[maxn],h[maxn];
struct xx{
int next;
ll n;
}vis[4*mod];
int head[mod],top,ans;
struct hashtable{
int hash(ll x){
return x%mod;
}
void clear(){
memset(head,-1,sizeof(head));
top=0;
}
void insert(ll x){
int value=hash(x);
vis[top]=(xx){head[value],x};
head[value]=top++;
}
bool find(ll x){
int value=hash(x);
for(int i=head[value];i!=-1;i=vis[i].next){
if(vis[i].n==x) return 1;
}
return 0;
}
}table;
void fen(int LL,int L,int l,int r){
if(l>r) return ;
table.clear();
int mid=(l+r)>>1;
int i;
for(i=0;i<=L-mid;++i){
table.insert(h[i]-h[i+mid]*xp[mid]);
}
bool ok=1;
for(i=0;i<=LL-mid;++i){
if(table.find(H[i]-H[i+mid]*xp[mid])){
ok=0;
ans=mid;
if(mid+1<=r) fen(LL,L,mid+1,r);
break;
}
}
if(ok && r-l>1) fen(LL,L,l,mid-1);
}
int main()
{
int T;
xp[0]=1;
for(int i=1;i<maxn;++i){
xp[i]=xp[i-1]*base;
}
scanf("%d",&T);
while(T--){
scanf("%s",a);
scanf("%s",b);
ans=0;
int A=strlen(a),B=strlen(b);
if(A>B){
H[A]=0;
for(int i=A-1;i>=0;--i){
H[i]=H[i+1]*base+a[i]-'a'+1;
}
h[B]=0;
for(int i=B-1;i>=0;--i){
h[i]=h[i+1]*base+b[i]-'a'+1;
}
fen(A,B,1,B);
}
else {
H[B]=0;
for(int i=B-1;i>=0;--i){
H[i]=H[i+1]*base+b[i]-'a'+1;
}
h[A]=0;
for(int i=A-1;i>=0;--i){
h[i]=h[i+1]*base+a[i]-'a'+1;
}
fen(B,A,1,A);
}
printf("%d\n",ans);
}
return 0;
}