求两个字符串的最长公共字串。练习模板的题..用后缀数组就把两个串拼起来,两串之间和末尾添加分隔符,然后扫一遍height数组,判断一下sa[i],sa[i-1]是不是在两个串里,是就更新最大值,否则Continue.刚学后缀数组的时候poj上C++,G++都没问题来着,而且当时那个模板还是错的- ...今重写了下结果C++各种RE,G++倒是一次过。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; typedef long long ll; const int maxn=420000; int s[maxn],rs[maxn]; int sa[maxn],t[maxn],t2[maxn],c[maxn]; int n,m,k,tt; char s1[maxn],s2[maxn]; int rank[maxn],height[maxn]; int l1,l2; inline int idx(char s) { return s-'a'+2; } void getheight(int n) { int i,j,k=0; for (i=0; i<=n; i++) rank[sa[i]]=i; for (i=0; i<n; i++) { if (k) k--; int j=sa[rank[i]-1]; while(s[i+k]==s[j+k]) k++; height[rank[i]]=k; } } void build_ss(int m,int n) { n++; int i,*x=t,*y=t2; for (int i=0; i<m; i++) c[i]=0; for (int i=0; i<n; i++) c[x[i]=s[i]]++; for (int i=1; i<m; i++) c[i]+=c[i-1]; for (int i=n-1; i>=0; i--) sa[--c[x[i]]]=i; for (int k=1; k<=n; k<<=1) { int p=0; for (i=n-k; i<n; i++) y[p++]=i; for (i=0; i<n; i++) if (sa[i]>=k) y[p++]=sa[i]-k; for (i=0; i<m; i++) c[i]=0; for (i=0; i<n; i++) c[x[y[i]]]++; for (i=1; i<m; i++) c[i]+=c[i-1]; for (i=n-1; i>=0; i--) sa[--c[x[y[i]]]] = y[i]; swap(x,y); p=1; x[sa[0]]=0; for (i=1; i<n; i++) x[sa[i]]=(y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k])? p-1 : p++; if (p>=n) break; m=p; } } bool diff(int x,int y) { int a=min(x,y); int b=max(x,y); if (a<l1 && b>l1) return true; return false; } int main() { // freopen("in.txt","r",stdin); while(~scanf("%s",s1)) { scanf("%s",s2); l1=strlen(s1); l2=strlen(s2); for (int i=0; i<l1; i++) s[i]=idx(s1[i]); s[l1]=0; n=l1+1; for (int i=0; i<l2; i++) { s[n++]=idx(s2[i]); } s[n]=1; build_ss(128,n); getheight(n); int ans=0; for (int i=2; i<n; i++) { if (diff(sa[i],sa[i-1])) ans=max(ans,height[i]); } printf("%d\n",ans); } return 0; }
刚学后缀自动机的话,这题拿来练习也挺合适的。用第一个串构建后缀自动机,之后拿第二个传在自动机上跑一遍,逐字符扫描,当前状态按这个字符向下走的状态非空的话,就转移并且tmp++,否则就沿着失配路径找到第一个可以按当前的字符向下转移的状态并且把tmp更新成now->val+1,找不到的话就回到根节点,tmp赋值成0.每次执行完都用tmp去更新一下最大值ans,第二个传扫完后答案也就出来了。用后缀自动机就正常了-C++,G++都没什么问题,而且毕竟是O(n)的,效率比倍增的SA好多了。
#include <iostream> #include <cstdio> #include <algorithm> #include <memory.h> #include <cmath> #include <string> #include <cstring> using namespace std; typedef long long ll; const int maxn=101000*4; const int S=26; int tot,len; int n,m; int wtop[maxn]; int c[maxn]; int k; int ans; struct node { node *par,*go[S]; int val,id; }*tail,*root,que[maxn],*top[maxn]; char str[maxn],s[maxn],ss[maxn]; inline int idx(char s) { return s-'a'; } struct SAM { void init(int m) { for (int i=0; i<=m; i++) { memset(que[i].go,0,sizeof que[i].go); que[i].id=que[i].val=0; } tot=0; len=1; root=tail=&que[tot++]; root->id=0; ans=0; } void add(int c,int l) { node* p=tail; node* np=&que[tot++]; np->val=l; np->id=tot-1; while(p && p->go[c]==NULL) p->go[c]=np,p=p->par; if (p==NULL) np->par=root; else { node *q=p->go[c]; if (p->val+1==q->val) np->par=q; else { node *nq=&que[tot++]; *nq=*q; nq->id=tot-1; nq->val=p->val+1; np->par=q->par=nq; while(p && p->go[c]==q) p->go[c]=nq,p=p->par; } } tail=np; } void debug_suff() { for (int i=0; i<tot; i++) { for (int c=0; c<S; c++) if (que[i].go[c]) { cout<<que[i].id<<" "<<que[i].go[c]->id<<endl; } } } void debug_pre() { for (int i=1; i<tot; i++) { cout<<que[i].id<<" "<<que[i].par->id<<endl; } } void TopS() { memset(c,0,sizeof c); for (int i=0; i<tot; i++) c[que[i].val]++; for (int i=1; i<len; i++) c[i]+=c[i-1]; for (int i=0; i<tot; i++) top[--c[que[i].val]]=&que[i],wtop[c[que[i].val]]=i; } int slove(char* s) { int res=0,tmp=0; node *p=root; int l=strlen(s); for(int i=0; i<l; i++) { int x=idx(s[i]); if (p->go[x]) { p=p->go[x]; tmp++; } else { while(p && p->go[x]==NULL)p=p->par; if (p) { tmp=p->val+1; p=p->go[x]; } else { p=root; tmp=0; } } res=max(res,tmp); } return res; } }sam; char s1[maxn],s2[maxn]; int main() { // freopen("in.txt","r",stdin); while(~scanf("%s",s1)) { scanf("%s",s2); int l1=strlen(s1); sam.init(2*l1); for (int i=0; i<l1; i++) sam.add(idx(s1[i]),len++); sam.TopS(); printf("%d\n",sam.slove(s2)); } return 0; }