题目描述
给出一个长度为n的字符串s[1],由小写字母组成。定义一个字符串序列s[1....k],满足性质:s[i]在s[i-1] (i>=2)中出现至少两次(位置可重叠),问最大的k是多少,使得从s[1]开始到s[k]都满足这样一个性质。
发现 $s[1...k]$ 之间一定是互为后缀关系. 那么就可以建出后缀树,令 $dp_{u}$ 表示 $u$ 节点代表子串的答案
维护 $top_{u}$ 表示 $u$ 以及 $u$ 在后缀树的祖先中合法的且答案最大(答案相同则最短)的节点编号
$dp_{u}\Rightarrow dp_{top_{fa}}+1$ ,$fa$ 在 $u$ 中出现大于等于2次
$dp_{u}=1,top_{u}=top_{fa}$,$fa$ 在 $u$ 中仅出现 $1$ 次
#include<bits/stdc++.h>
#define maxn 400002
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
namespace tr
{
#define lson t[x].l
#define rson t[x].r
#define mid ((l+r)>>1)
int cnt;
struct Node { int l,r; }t[maxn*20];
void modify(int &x,int l,int r,int k)
{
if(!x) x=++cnt;
if(l==r) return;
if(k<=mid) modify(lson,l,mid,k);
else modify(rson,mid+1,r,k);
}
int merge(int u,int v)
{
if(!u||!v) return u+v;
int x=++cnt;
lson=merge(t[u].l,t[v].l);
rson=merge(t[u].r,t[v].r);
return x;
}
int query(int x,int l,int r,int L,int R)
{
if(!x) return 0;
if(l>=L&&r<=R) return 1;
int tmp=0;
if(L<=mid) tmp+=query(lson,l,mid,L,R);
if(R>mid) tmp+=query(rson,mid+1,r,L,R);
return tmp;
}
};
namespace SAM
{
char str[maxn];
int last,tot,n;
int trans[maxn][27],f[maxn],len[maxn],C[maxn],rk[maxn],top[maxn],dp[maxn],pos[maxn],rt[maxn];
void init() { last=tot=1; }
void extend(int c,int i)
{
int np=++tot,p=last;
len[np]=len[p]+1,last=np;
while(p&&!trans[p][c]) trans[p][c]=np,p=f[p];
if(!p) f[np]=1;
else
{
int q=trans[p][c];
if(len[q]==len[p]+1) f[np]=q;
else
{
int nq=++tot;
len[nq]=len[p]+1;
pos[nq]=pos[q];
memcpy(trans[nq],trans[q],sizeof(trans[q]));
f[nq]=f[q], f[np]=f[q]=nq;
while(p&&trans[p][c]==q) trans[p][c]=nq,p=f[p];
}
}
pos[np]=i;
tr::modify(rt[last],1,n,i);
}
void prepare()
{
int i,j;
init();
scanf("%d%s",&n,str+1);
for(i=1;i<=n;++i) extend(str[i]-'a',i);
for(i=1;i<=tot;++i) ++C[len[i]];
for(i=1;i<=tot;++i) C[i]+=C[i-1];
for(i=1;i<=tot;++i) rk[C[len[i]]--]=i;
for(i=tot;i>1;--i)
{
int u=rk[i];
rt[f[u]]=tr::merge(rt[f[u]],rt[u]);
}
}
void calc()
{
int i,j,ans=1;
for(i=2;i<=tot;++i)
{
int u=rk[i],ff=f[rk[i]];
if(ff==1) { top[u]=u,dp[u]=1; continue; }
if(tr::query(rt[top[ff]],1,n,pos[u]-len[u]+len[top[ff]],pos[u]-1))
top[u]=u,dp[u]=dp[top[ff]]+1;
else
top[u]=top[ff];
ans=max(ans,dp[u]);
}
printf("%d\n",ans);
}
};
int main()
{
//msetIO("input");
SAM::prepare();
SAM::calc();
return 0;
}