题解 SP687【REPEATS - Repeats】

$\text{Link}$

题意

给出一个长度为 $n$ 的字符串 $s$,求最大的 $k$ 使得 $s$ 有子串满足其是由任意一个字符串 $t$ 重复拼接 $k$ 次而成的。多组数据。

$T\le 20,n\le 5\times 10^4$。

思路

这是一篇 $\text{SAM}$ 题解!

与我同样做法的题解可能说得不是很清楚(我不太看得懂),于是我也来写一篇。

根据 P4391 的结论,我们可以往 $\text{border}$ 的方向考虑。

如果我们枚举 $\text{border}$,设前缀为 $A=s[l,q]$,后缀为 $A=s[p,r]$,总串为 $B=s[l,r]$,我们要求 $p\le q$。由 P4391 的结论,我们知道 $s[l,r]$ 是可以由 $s[q+1,r]$ 重复并截取一个后缀得到。这里我们要忽略最后被截掉的部分,得到重复次数是 $\displaystyle\lfloor\dfrac{r-l+1}{r-q}\rfloor$。

考虑这个 $\text{border}$ 是 $s$ 的一个子串,如果要枚举 $\text{border}$ 并且求出它在 $s$ 中的结束位置,我们自然会选择 $\text{SAM}$。

建出 $\text{SAM}$ 后,我们枚举结点 $i$,考虑它作为 $\text{border}$ 时的贡献。由于我们要知道结束位置相关的信息,需要线段树合并求出 $\text{endpos}$。为了方便,我们将上文中式子转化为 $\displaystyle\lfloor\dfrac{q-l+1}{r-q}\rfloor+1$,自然,我们要让 $q-l+1$ 最大且 $r-q$ 最小。易得,$q-l+1$ 的最大值是 $len_i$,$r-q$ 的最小值是在 $\text{endpos}$ 中的任意两个元素 $x,y(x<y)$,$y-x$ 的最小值。对于后者,我们直接在线段树上维护即可。

于是我们就得到了这个结点的贡献 $\displaystyle\lfloor\dfrac{len_i}{\min_{x,y\in\text{endpos}(i),x<y}(y-x)}\rfloor+1$。对所有的贡献取 $\max$ 即可。

时间复杂度 $O(\sum n\log n)$。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff

}
const int N=1e5+10;
struct node{
    int ml,mr,md;
    inline friend node operator+(const node &a, const node &b){
        node c;
        c.ml=min(a.ml,b.ml),c.mr=max(a.mr,b.mr);
        c.md=min({a.md,b.md,b.ml-a.mr});
        return c;
    }
    node(){ ml=md=1e9,mr=0; }
};
struct Edge{
    int to,nxt;
}b[N];
int T,n,ans;
int head[N],cnt;
inline void add(int u,int v){
    cnt++;
    b[cnt].to=v;
    b[cnt].nxt=head[u];
    head[u]=cnt;
}
struct Segument_Tree{
    int son[2][N*20],root[N],cnt;
    node mes[N*20];
    #define ls (son[0][rt])
    #define rs (son[1][rt])
    inline void pushup(int rt){
        mes[rt]=mes[ls]+mes[rs];
    }
    inline void insert(int &rt,int l,int r,int p){
        if(!rt)
            rt=++cnt;
        if(l==r){
            mes[rt].ml=mes[rt].mr=l;
            mes[rt].md=1e9;
            return ;
        }
        int mid=l+r>>1;
        if(p<=mid) insert(ls,l,mid,p);
        else insert(rs,mid+1,r,p);
        pushup(rt);
    }
    inline int merge(int a,int b,int l,int r){
        if(!a||!b) return a+b;
        int rt=++cnt;
        if(l==r) return rt;
        int mid=l+r>>1;
        ls=merge(son[0][a],son[0][b],l,mid);
        rs=merge(son[1][a],son[1][b],mid+1,r);
        pushup(rt);
        return rt;
    }
    inline int query(int rt){
        return mes[rt].md;
    }
    inline void clear(){
        for(int i=1;i<=cnt;i++) 
            mes[i]=node(),son[0][i]=son[1][i]=0;
        cnt=0;
    }
}t;
struct SAM{
    struct statu{
        int len,link;
        int ch[26];
    }a[N];
    int siz,last;
    SAM(){
        a[0].len=0;
        a[0].link=-1;
        last=0;
    }
    inline void insert(int c,int i){
        int cur=++siz;
        a[cur].len=a[last].len+1;
        t.insert(t.root[cur],1,n,i);
        int p=last;
        while(p!=-1&&!a[p].ch[c]){
            a[p].ch[c]=cur;
            p=a[p].link;
        }
        if(~p){
            int q=a[p].ch[c];
            if(a[p].len+1==a[q].len){
                a[cur].link=q;
            }else{
                int clone=++siz;
                a[clone]=a[q];
                a[clone].len=a[p].len+1;
                while(p!=-1&&a[p].ch[c]==q){
                    a[p].ch[c]=clone;
                    p=a[p].link;
                }
                a[q].link=a[cur].link=clone;
            }
        }else{
            a[cur].link=0;
        }
        last=cur;
    }
    inline void clear(){
        for(int i=0;i<=siz;i++){
            memset(a[i].ch,0,sizeof(a[i].ch));
            a[i].len=a[i].link=0;
        }
        a[0].len=0,a[0].link=-1;
        siz=last=0;
    }
    inline void build(int n){
        static char str[N];
        for(int i=1;i<=n;i++)
            insert(getc()-'a',i);
        for(int i=1;i<=siz;i++)
            add(a[i].link,i);
    }
    inline void dfs(int rt){
        for(int i=head[rt];i;i=b[i].nxt){
            dfs(b[i].to);
            t.root[rt]=t.merge(t.root[rt],t.root[b[i].to],1,n);
        }
        ans=max(ans,a[rt].len/t.query(t.root[rt])+1);
    }
}sam;
inline void clear(){
    for(int i=0;i<=sam.siz;i++)
        t.root[i]=head[i]=0;
    sam.clear(),t.clear();
    cnt=0;
}
int main(){
    T=read();
    while(T--){
        n=read(),ans=0;
        sam.build(n);
        sam.dfs(0);
        write(ans),putc('\n');
        clear();
    }
    flush();
    return 0;
}

再见 qwq~

posted @ 2022-04-26 18:17  ffffyc  阅读(16)  评论(0)    收藏  举报  来源