POJ2274 Long Long Message 字符串
正解:SA/哈希+二分
解题报告:
啊先放下翻译,,,?大意就有两个字符串,求这两个字符串的最长公共子串
先港SA的做法趴
就把两个子串拼接起来,然后题目就变成了求后缀的最长公共前缀了
所以就跑一下SA的模板就欧克了
只是注意两个细节,,,
一个是因为要求的是两个字符串的最长公共子串,所以要判断一下确保两个子串并不都属于一个串中的
另一个是拼起来的时候要在中间加个特殊字符比如'#'这种的,原因很显然?或者放个hack数据也许更好理解趴QAQ
aaaab
bbbbb
如果不加答案就会是5,然而显然答案是1,自己意会下就好
然后说下二分+哈希
就直接二分一个长度鸭,然后把所有这个长度的找出来,哈希一下,判断是否有相同的就好
具体就先把第一个串的这个长度的串哈希了,然后对第二个串一个个做,每算出一个子串的哈希值就二分查找下
然后get了一个二分查找的函数,,,binary_search
(其实可以直接用lower_bound然后判是否相等来着hhhhh
二分+哈希的代码我没打,,,只写了个SA的就只放SA的代码了QAQ?
#include<algorithm> #include<iomanip> #include<cstring> #include<cstdio> #include<string> using namespace std; #define il inline #define gc getchar() #define ll long long #define ull unsigned ll #define ri register int #define rb register bool #define rc register char #define rp(i,x,y) for(ri i=x;i<=y;++i) #define my(i,x,y) for(ri i=x;i>=y;--i) const int N=220000; int sa[N],x[N],y[N],t[N],n,rk[N],hei[N],str[N],n1,n2,as; char ch[N]; il bool check(ri gd,ri gs,ri k){return y[gd]==y[gs] && y[gd+k]==y[gs+k];} il bool jud(ri gd,ri gs){return (gd<=n1 && gs>n1) || (gs<=n1 && gd>n1);} il void SA() { ri m=150; rp(i,1,n)++t[x[i]=str[i]]; rp(i,1,m)t[i]+=t[i-1]; my(i,n,1)sa[t[x[i]]--]=i; for(ri k=1;k<=n;k<<=1) { ri p=0; rp(i,0,m)t[i]=0;rp(i,0,n)y[i]=0; rp(i,n-k+1,n)y[++p]=i; rp(i,1,n)if(sa[i]>k)y[++p]=sa[i]-k; rp(i,1,n)++t[x[y[i]]]; rp(i,1,m)t[i]+=t[i-1]; my(i,n,1)sa[t[x[y[i]]]--]=y[i]; swap(x,y); x[sa[1]]=p=1; rp(i,2,n)x[sa[i]]=check(sa[i],sa[i-1],k)?p:++p; if(p>=n)break; m=p; } rp(i,1,n)rk[sa[i]]=i; ri h=0; rp(i,1,n) { if(h)--h; while(str[i+h]==str[sa[rk[i]-1]+h])++h; hei[rk[i]]=h; } } int main() { // freopen("2774.in","r",stdin);freopen("2774.out","w",stdout); scanf("%s",ch+1);n1=strlen(ch+1);rp(i,1,n1)str[++n]=ch[i]-'a'+1;str[++n]='#'; scanf("%s",ch+1);n2=strlen(ch+1);rp(i,1,n2)str[++n]=ch[i]-'a'+1; SA(); rp(i,2,n)if(jud(sa[i-1],sa[i]))as=max(as,hei[i]); printf("%d\n",as); return 0; } /* memcpy比swap快,,,mk */