某考试 T1 str
一开始死磕sam,发现根本没法做。。。。。。
后来想了想,反正匹配子串的大部分不是sam就是 二分+hash啊,,,于是就想了想二分+hash,发现好像可以做啊!
就是假设我们要让 s1[1] 映射到s2 中的位置是 s2[i] ,那么这种情况的答案就很好算了,就是求一次lcp之后把第一个不匹配的钦定成匹配之后再一次lcp。
所以总的时间复杂度就是 O(N * log(N)) 啦。
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #define ll unsigned long long using namespace std; const int maxn=140005,BASE=2875; char s[maxn],S[maxn]; ll h[maxn],H[maxn],ci[maxn]; int n,m,ans; inline bool EQ(int b,int B,int len){ if(b+len-1>n||B+len-1>m) return 0; return h[b+len-1]-h[b-1]*ci[len]==H[B+len-1]-H[B-1]*ci[len]; } int main(){ freopen("str.in","r",stdin); freopen("str.out","w",stdout); scanf("%s%s",s+1,S+1),ci[0]=1; n=strlen(s+1),m=strlen(S+1); s[n+1]='6',n++,S[m+1]='~',m++; for(int i=1;i<=n;i++) h[i]=h[i-1]*(ll)BASE+(ll)s[i]; for(int i=1;i<=m;i++) H[i]=H[i-1]*(ll)BASE+(ll)S[i]; for(int i=1;i<=max(n,m);i++) ci[i]=ci[i-1]*(ll)BASE; for(int i=1;i<=m;i++){ int l=0,r=n,mid,an; while(l<=r){ mid=l+r>>1; if(EQ(1,i,mid)) l=mid+1,an=mid; else r=mid-1; } if(an==n){ ans=an; break; } l=0,r=n-an-1; while(l<=r){ mid=l+r>>1; if(EQ(an+2,i+an+1,mid)) l=mid+1,ans=max(ans,an+mid+1); else r=mid-1; } } printf("%d\n",ans); return 0; }
我爱学习,学习使我快乐