这个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;
}