[cf700E][后缀自动机]Cool Slogans

版权声明:他无力阻止你的转载 https://blog.csdn.net/qq_36993218/article/details/79699818

E. Cool Slogans
time limit per test4 seconds
memory limit per test512 megabytes
inputstandard input
outputstandard output
Bomboslav set up a branding agency and now helps companies to create new logos and advertising slogans. In term of this problems, slogan of the company should be a non-empty substring of its name. For example, if the company name is “hornsandhoofs”, then substrings “sand” and “hor” could be its slogans, while strings “e” and “hornss” can not.

Sometimes the company performs rebranding and changes its slogan. Slogan A is considered to be cooler than slogan B if B appears in A as a substring at least twice (this occurrences are allowed to overlap). For example, slogan A =  “abacaba” is cooler than slogan B =  “ba”, slogan A =  “abcbcbe” is cooler than slogan B =  “bcb”, but slogan A =  “aaaaaa” is not cooler than slogan B =  “aba”.

You are given the company name w and your task is to help Bomboslav determine the length of the longest sequence of slogans s1, s2, …, sk, such that any slogan in the sequence is cooler than the previous one.

Input
The first line of the input contains a single integer n (1 ≤ n ≤ 200 000) — the length of the company name that asks Bomboslav to help. The second line contains the string w of length n, that consists of lowercase English letters.

Output
Print a single integer — the maximum possible length of the sequence of slogans of the company named w, such that any slogan in the sequence (except the first one) is cooler than the previous

Examples
inputCopy
3
abc
output
1
inputCopy
5
ddddd
output
5
inputCopy
11
abracadabra
output
3

sol:

考虑这道题实际上选出一个串,然后在这个串中选出现了2次的子串。
假设选出来的串是s1,s2,s3…sn
我们发现si+1在si中出现的位置如果是x和y,我们总能删掉他x前面和y+len后面的东西使得si+1成为si的border,并且不会使得答案更劣。于是问题转化成了i,j这个子串的价值为他的boder+1。我们考虑因为涉及了子串问题所以我们把他丢到sam上面去做。一个状态中的子串显然是等价的,因为他们的祖先显然是这些子串的后缀,把他们单独拿出来不会使得他的后缀变得更多,并不会使答案增加。我们只要考虑这些祖先是否在这个子串中出现了2次即可。因为出现了两次,我们完全可以把前面的部分砍掉使得他的祖先成为一个boder。那么判断祖先是否在这个子串中出现了2次只要随便从当前状态取出一个right集合的点x,判断祖先的right集合是否出现在[x-val+1,x]2次即可。

#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

inline int read()
{
    char c;
    bool pd=0;
    while((c=getchar())>'9'||c<'0')
    if(c=='-') pd=1;
    int res=c-'0';
    while((c=getchar())>='0'&&c<='9')
    res=(res<<3)+(res<<1)+c-'0';
    return pd?-res:res;
}
int cnt=1,last=1;
const int N=410000;
int val[N],go[N][26],par[N];
inline void extend(int x)
{
    int p=last;
    int np=last=++cnt;
    val[np]=val[p]+1;
    while(!go[p][x]) go[p][x]=np,p=par[p];
    if(!p) par[np]=1;
    else
    {
        int q=go[p][x];
        if(val[q]==val[p]+1) par[np]=q;
        else
        {
            int nq=++cnt;
            val[nq]=val[p]+1;
            par[nq]=par[q];
            for(int i=0;i<=25;++i) go[nq][i]=go[q][i];
            par[q]=par[np]=nq;
            while(go[p][x]==q) go[p][x]=nq,p=par[p];
        }
    }
}
int tot,fir[N],ed[N*2],nex[N*2];
inline void add(int x,int y)
{
    nex[++tot]=fir[x];fir[x]=tot;ed[tot]=y;
    nex[++tot]=fir[y];fir[y]=tot;ed[tot]=x;
}
int rt[N],key;
const int M=N*20;
int lc[M],rc[M],size[M];
inline int merge(int x,int y)
{
    if(!x) return y;
    if(!y) return x;
    int now=++key;
    size[now]=size[x]+size[y];
    lc[now]=merge(lc[x],lc[y]);
    rc[now]=merge(rc[x],rc[y]);
    return now;
}
inline void modify(int &k,int l,int r,int x)
{
    if(!k) k=++key;
    size[k]++;
    if(l==r) return;
    int mid=l+r>>1;
    if(mid>=x) modify(lc[k],l,mid,x);
    else modify(rc[k],mid+1,r,x);
}
inline void query(int k,int l,int r,int L,int R,int &res)
{
    if(!k) return;
    if(L<=l&&r<=R)
    {
        res+=size[k];
        return;
    }
    int mid=l+r>>1;
    if(mid>=L) query(lc[k],l,mid,L,R,res);
    if(mid< R) query(rc[k],mid+1,r,L,R,res);
}
int R[N],pos[N];
int father[N];
inline void dfs(int u,int fa)
{
    int e,v;
    father[u]=fa;
    if(pos[u])
    {
        modify(rt[u],1,cnt,pos[u]);
        R[u]=pos[u];
    }
    for(e=fir[u];v=ed[e],e;e=nex[e])
    if(v!=fa)
    {
        dfs(v,u);
        rt[u]=merge(rt[u],rt[v]);
        R[u]=max(R[u],R[v]);
    }
}
int ans[N];
int dep[N];
int fans;
int tfa[N];
inline void get_ans(int u,int fa)
{
    int e,v;
    dep[u]=dep[fa]+1;
    for(e=fir[u];v=ed[e],e;e=nex[e])
    if(v!=fa)
    {
        int res=0;
        if(u!=1) query(rt[tfa[u]],1,cnt,R[v]-val[v]+val[father[tfa[u]]]+1,R[v],res);
        if(res>=2||u==1) ans[v]=ans[u]+1,tfa[v]=v;
        else ans[v]=ans[u],tfa[v]=tfa[u];
        if(fans<ans[v]) fans=ans[v];
        get_ans(v,u);
    }
}
char sr[N];
int n;
int main()
{
//  freopen("a.in","r",stdin);
//  freopen("a.out","w",stdout);
    n=read();
    scanf("%s",sr+1);
//  n=strlen(sr+1);
    int anser;
    for(int i=1;i<=n;++i)
    {
        pos[cnt+1]=i;
        if(i==n) anser=cnt+1;
        extend(sr[i]-'a');
    }
    for(int i=1;i<=cnt;++i)
    if(par[i]) add(par[i],i);
    dfs(1,0);
//  dfs();
    get_ans(1,0);
    cout<<fans<<endl;
}
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页