这个ac自动机做法貌似很显然
然而我用的后缀数组(专业制造麻烦……其实就是为了练后缀数组)
这题二分答案会有很多坑爹的地方
原因就是这height数组存的是suffix(sa[i])和suffix(sa[i-1])的LCP
二分答案的时候要注意
不过貌似直接暴力找也挺快
orz ws_fqk 暴力虐二分……
#include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<queue> #include<vector> #include<set> #include<map> #include<iostream> #include<algorithm> #define T 1111111 using namespace std; char s[T]; int t1[T],t2[T],cc[T],rank[T],sa[T],height[T]; int len,n,st[T],L[T],h[T][20]; bool cmp(int *y,int a,int b,int k) { int a1=y[a],b1=y[b]; int a2=a+k>=len?-1:y[a+k]; int b2=b+k>=len?-1:y[b+k]; return a1==b1&&a2==b2; } void make_sa() { int *x=t1,*y=t2,m=433; for(int i=0;i<m;i++)cc[i]=0; for(int i=0;i<len;i++)++cc[x[i]=s[i]]; for(int i=1;i<m;i++)cc[i]+=cc[i-1]; for(int i=len-1;~i;i--)sa[--cc[x[i]]]=i; for(int k=1;k<len;k<<=1) { int p=0; for(int i=len-k;i<len;i++)y[p++]=i; for(int i=0;i<len;i++)if(sa[i]>=k)y[p++]=sa[i]-k; for(int i=0;i<m;i++)cc[i]=0; for(int i=0;i<len;i++)++cc[x[y[i]]]; for(int i=1;i<m;i++)cc[i]+=cc[i-1]; for(int i=len-1;~i;i--)sa[--cc[x[y[i]]]]=y[i]; swap(x,y),m=1,x[sa[0]]=0; for(int i=1;i<len;i++)x[sa[i]]=cmp(y,sa[i],sa[i-1],k)?m-1:m++; if(m>=len)return; } } void make_height() { int k=0; for(int i=0;i<len;i++)rank[sa[i]]=i; for(int i=0;i<len;i++) { if(!rank[i])continue; int j=sa[rank[i]-1]; if(k)k--; while(s[i+k]==s[j+k])k++; height[rank[i]]=k; //cout <<i <<" "<< rank[i] << " "<< k << endl; } } void make_stt() { for(int i=0;i<len;i++)h[i][0]=height[i];//cout << height[i] <<" "; for(int k=1;(1<<k)<=len;k++) for(int i=0;i<len;i++) { if(i+(1<<k)>len)break; h[i][k]=min(h[i][k-1],h[i+(1<<k-1)][k-1]); } } int ask(int l,int r) { if(l>r)return T; int k=log2(r-l+1); int mn=min(h[l][k],h[r-(1<<k)+1][k]); return mn; } int ask_pre(int R,int x) { int l=1,r=R,ans=R+1; while(l<=r) { int mid=l+r>>1; if(ask(mid,R)>=x)ans=mid,r=mid-1; else l=mid+1; } return ans-1; } int ask_nxt(int L,int x) { int l=L+1,r=len-1,ans=L; while(l<=r) { int mid=l+r>>1; if(ask(L+1,mid)>=x)ans=mid,l=mid+1; else r=mid-1; } return ans; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%s",s+len); st[i]=len; L[i]=strlen(s+len); len+=L[i]; s[len]='$'; len++; } make_sa(); make_height(); make_stt(); for(int i=1;i<=n;i++) { int l=ask_pre(rank[st[i]],L[i]); int r=ask_nxt(rank[st[i]],L[i]); printf("%d\n",r-l+1); } return 0; }