[CF700E]Cool Slogans

Posted by Dispwnl on January 14, 2019

题目

题目大意

给定一个字符串$S$,现在要找$S$中的一个子串$T$,找到$T$中出现过不少于两次的子串$A$,使得$T=A$,然后重复这个操作

求最多能执行多少次

Examples

input

3
abc

output

1

input

5
ddddd

output

5

input

11
abracadabra

output

3

题解

假设已经知道$T$是哪个状态(姑且定为$t$)了,那么接下来找的$A$的状态$a$肯定是后缀树$t$的某个祖先

所以查询转移到$t$的父亲的状态$t’$子树里$[endpos_t-len_t+len_{t’},endpos_t-1]$中是否存在节点,有的话说明可以转移,否则说明$t$可以替换$t$的父亲(长度增加)

从上到下转移下来,中间的最大值就是答案

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<algorithm>
# define ID id[i]
# define tl s[k].l
# define tr s[k].r
# define mid (l+r>>1)
using namespace std;
const int MAX=5e5+10;
struct p{
	int l,r;
}s[MAX<<5];
int n,tot,ans;
int rt[MAX];
char a[MAX];
void change(int l,int r,int &k,int x)
{
	if(!k) k=++tot;
	if(l==r) return;
	if(x<=mid) change(l,mid,tl,x);
	else change(mid+1,r,tr,x);
}
int merge(int x,int y)
{
	if(!x||!y) return x+y;
	int k=++tot;
	return tl=merge(s[x].l,s[y].l),tr=merge(s[x].r,s[y].r),k;
}
bool ask(int l,int r,int k,int L,int R)
{
	if(!k||r<L||R<l) return 0;
	if(l>=L&&r<=R) return 1;
	if(ask(l,mid,tl,L,R)) return 1;
	return ask(mid+1,r,tr,L,R);
}
struct SAM{
	int l,r,L;
	int len[MAX],fa[MAX],pos[MAX],f[MAX],id[MAX],tax[MAX],_fa[MAX];
	int son[MAX][26];
	SAM() {l=r=1;}
	void ins(int x,int id)
	{
		int tt=r;
		len[r=++l]=++L,change(1,n,rt[r],pos[r]=id);
		for(;tt&&!son[tt][x];tt=fa[tt])
		  son[tt][x]=r;
		if(!tt) return void(fa[r]=1);
		int qwq=son[tt][x];
		if(len[qwq]==len[tt]+1) return void(fa[r]=qwq);
		len[++l]=len[tt]+1,fa[l]=fa[qwq],fa[qwq]=fa[r]=l,change(1,n,rt[l],pos[l]=id);
		for(int i=0;i<26;++i)
		  son[l][i]=son[qwq][i];
		for(int i=tt;son[i][x]==qwq;i=fa[i])
		  son[i][x]=l;
	}
	void Init()
	{
		for(int i=1;i<=l;++i)
		  ++tax[len[i]];
		for(int i=1;i<=n;++i)
		  tax[i]+=tax[i-1];
		for(int i=l;i>=1;--i)
		  id[tax[len[i]]--]=i;
		for(int i=l;i>=1;--i)
		  if(fa[ID]) rt[fa[ID]]=merge(rt[fa[ID]],rt[ID]);
	}
	void Solve()
	{
		Init();
		for(int i=1;i<=l;++i)
		  {
		  	if(fa[ID]==1) _fa[ID]=ID,f[ID]=1;
		  	else if(ask(1,n,rt[_fa[fa[ID]]],pos[ID]-len[ID]+len[_fa[fa[ID]]],pos[ID]-1)) f[ID]=f[_fa[fa[ID]]]+1,_fa[ID]=ID;
		  	else f[ID]=f[fa[ID]],_fa[ID]=_fa[fa[ID]];
		  	ans=max(ans,f[ID]);
		  }
		printf("%d",ans);
	}
}_S;
int main()
{
	scanf("%d%s",&n,a+1);
	for(int i=1;i<=n;++i)
	  _S.ins(a[i]-'a',i);
	return _S.Solve(),0;
}