CF1063F String Journey

Link
我们可以发现最后选出来的串的长度一定是(ans,cdots,1)
因为若连续的两个串长度为(i+2,i),那么一定可以通过把长度为(i+2)的串删除首/尾的字符使得长度连续且答案不劣。
(f_i)表示强制(str_i)为某个答案串的开头时(suf(i))的答案。
考虑枚举后一个答案串的开头(j),那么(f_i=max{f_j|j-f_j>iwedge sub(j,j+f_j-1)subseteq sub(i,i+f_j)}+1)
我们知道(f_ile f_{i+1}+1),因此我们可以枚举(f_i)进行检查,最多检查(O(n))次。
我们知道(jge i+f_i),而(i+f_i)不增,因此(j)不增,双指针维护合法的(j)区间即可。(此处合法只考虑(j-f_j>i)的限制,忽略(sub(j,j+f_j-1)subseteq sub(i,i+f_j))的限制)
由于(f_j>f_i)也算合法,因此我们实际上需要保证的是(sub(i,i+f_i-2))(sub(i+1,i+f_i-1))是某个(sub(j,j+f_j-1))的前缀。
在反串SAM的parent上处理出倍增数组,然后dfs序+线段树随便维护一下就好了。

#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
const int N=1000007;
char str[N];int cnt=1,now=1,trans[N][26],len[N],link[N],pos[N],fa[N][20],st[N],ed[N],f[N],t[4*N];
std::vector<int>e[N];
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)/2)
void update(int p,int l,int r,int x,int v)
{
    if(t[p]=std::max(t[p],v),l==r) return ;
    x<=mid? update(ls,l,mid,x,v):update(rs,mid+1,r,x,v);
}
int query(int p,int l,int r,int L,int R)
{
    if(l>R||L>r||L>R) return 0;
    if(L<=l&&r<=R) return t[p];
    return std::max(query(ls,l,mid,L,R),query(rs,mid+1,r,L,R));
}
#undef ls
#undef rs
#undef mid
void extend(int c)
{
    int p=now,q;now=++cnt,len[now]=len[p]+1,pos[len[now]]=now;
    for(;p&&!trans[p][c];p=link[p]) trans[p][c]=now;
    if(!p) return link[now]=1,void();
    if(len[q=trans[p][c]]==len[p]+1) return link[now]=q,void();
    link[++cnt]=link[q],memcpy(trans[cnt],trans[q],104),len[cnt]=len[p]+1,link[now]=link[q]=cnt,pos[cnt]=pos[q];
    for(;trans[p][c]==q;p=link[p]) trans[p][c]=cnt;
}
void dfs(int u)
{
    static int tim;st[u]=++tim,fa[u][0]=link[u];
    for(int i=1;i<20;++i) fa[u][i]=fa[fa[u][i-1]][i-1];
    for(int v:e[u]) dfs(v);
    ed[u]=tim;
}
int jump(int x,int l)
{
    x=pos[x];
    for(int i=19;~i;--i) if(len[fa[x][i]]>=l) x=fa[x][i];
    return x;
}
int check(int x,int l,int pos=0){return x>=l&&(l==1||(pos=jump(x,l-1),query(1,1,cnt,st[pos],ed[pos])+1>=l)||(pos=jump(x-1,l-1),query(1,1,cnt,st[pos],ed[pos])+1>=l));}
int main()
{
    int n,ans=0;
    scanf("%d%s",&n,str+1),std::reverse(str+1,str+n+1);
    for(int i=1;i<=n;++i) extend(str[i]-'a');
    for(int i=2;i<=cnt;++i) e[link[i]].push_back(i);
    dfs(1);
    for(int i=1,j=0;i<=n;++i)
    {
	f[i]=f[i-1]+1;
	while(!check(i,f[i])) --f[i],++j,update(1,1,cnt,st[jump(j,f[j])],f[j]);
	ans=std::max(ans,f[i]);
    }
    printf("%d",ans);
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/13038817.html