• [CF700E](Cool Slogans)


    QY 大神仙:这就是SAM大水题,快切快切

    然而还没怎么理解SAM的我表示对着题解一脸懵逼

    设原串为s;

    对于后缀自动机上的一个点i,定义dp[i]为点i表示的字符串的答案(最长嵌套次数)

    显然点i应从fa[i],fa[fa[i]]等endpos包含endpos(i)的节点转移过来,为什么呢?

    因为后缀自动机的性质,fa[i]所代表的字符串都是i所代表的字符串的后缀(endpos),如果答案(嵌套的字符串)不包含s[endpos(i)]的话,就不用i去更新。

    举个栗子(from here)

     

    这里的4号节点,也就是(len最长的字符串)aab,它的father是1,也就是意味着它的答案没法更新(dp[4]=1)

    可是aab里面有两个a,理论上答案是2,但因为3号节点(也就是aa)已经能通过fa[3]=2号节点来转移达到dp[3]=2;

    所以4号节点需要管的转移只有它的后缀,也就是它的fa所包含的字符,真的只是fa[i]吗?注意到其实是fa[i],fa[fa[i]],fa[fa[fa[i]]]等fa树上一路跳上去的节点

    好,那么我们得出(其实都是博主在瞎扯)点i只需从fa[i],fa[fa[i]]等节点转移过来,

    由于字符串i嵌套字符串fa[i]肯定比嵌套字符串fa[fa[i]]难,所以我们记top[i]为i的fa树路径上最浅的dp值等于dp[i]的位置,也就是说从top[i]到i都没有嵌套来更新dp值

    那么i就可以从top[fa]转移过来而不是从fa树上一路跳上去更新

    那么还剩下具体的更新部分,也就是怎么判节点top[fa[a]]代表的字符串在节点a代表的字符串中出现了两次呢?

    这里我们用endpos来判断,如果top[fa[a]]的至少两个endpos在a代表的最长字符串所覆盖的区间里出现过就成立

    因为top[fa[a]]是a的后缀,所以肯定已经出现了一次,所以只要在(pos[a]-len[a]+len[top[fa[a]]],pos[a]-1)中出现过一次即可

    等等,这是什么式子?

    这里 pos[a]为a代表的最长字符串的最后一个字符在原串s中的位置,len[a]为a代表的最长字符串的长度

    那么pos[a]-len[a]+1 到pos[a]即a代表的最长字符串所覆盖的区间,当然top[fa[a]]的endpos当然是不能在区间前len[top[fa[a]]-1的点出现的,不然还是越界

    又因为top[fa[a]]的endpos在pos[a]肯定出现过一次所以要把这个点舍掉,那么这就是整个式子了

    至于怎么维护一个节点的endpos集合,线段树合并即可。

    (扯完了,上code):

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define N 400004
    #define mid (l+r>>1)
    using namespace std;
    struct seg {
        int L[N*20],R[N*20],tot;
        void init() {
            tot=0;
            }
        void insert(int &now,int l,int r,int pos) {
            if(!now)now=++tot;
            if(l==r)return;
            if(pos<=mid)insert(L[now],l,mid,pos);
            else insert(R[now],mid+1,r,pos);
            }
        int merge(int A,int B) {
            if(!A||!B)return A+B;
            int it=++tot;
            L[it]=merge(L[A],L[B]);
            R[it]=merge(R[A],R[B]);
            return it;
            }
        int query(int now,int l,int r,int nl,int nr) {
            if(!now)return 0;
            if(nl<=l&&r<=nr)return 1;
            if(nl<=mid&&query(L[now],l,mid,nl,nr))return 1;
            if(mid<nr&&query(R[now],mid+1,r,nl,nr))return 1;
            return 0;
            }
        } aux;
    int rt[N];
    struct SAM {
        int cnt,las;
        int len[N],fa[N],ch[N][26],pos[N];
        void init() {
            cnt=las=1;
            }
        void add(int c,int pi) {
            int p=las,it=las=++cnt;
            len[it]=len[p]+1,pos[it]=pi;
            for(; p&&!ch[p][c]; p=fa[p])ch[p][c]=it;
            if(!p)fa[it]=1;
            else {
                int q=ch[p][c];
                if(len[q]==len[p]+1)fa[it]=q;
                else {
                    int np=++cnt;
                    for(int i=0; i<26; i++)ch[np][i]=ch[q][i];
                    len[np]=len[p]+1,pos[np]=pos[q];
                    fa[np]=fa[q],fa[q]=fa[it]=np;
                    for(; p&&ch[p][c]==q; p=fa[p])ch[p][c]=np;
                    }
                }
            }
        } sett;
    void init() {
        sett.init(),aux.init();
        }
    int n,tax[N],poi[N];
    int dp[N],top[N];
    char op[N];
    int ans=1;
    int main() {
        init();
        scanf("%d",&n);
        scanf("%s",op+1);
        for(int i=1; i<=n; i++) sett.add(op[i]-'a',i),aux.insert(rt[sett.las],1,n,i);
        for(int i=1; i<=sett.cnt; i++)tax[sett.len[i]]++;
        for(int i=1; i<=n; i++)tax[i]+=tax[i-1];
        for(int i=sett.cnt; i>=1; i--)poi[tax[sett.len[i]]--]=i;
        for(int i=sett.cnt; i>1; i--)
    rt[sett.fa[poi[i]]]=aux.merge(rt[sett.fa[poi[i]]],rt[poi[i]]); for(int i=2; i<=sett.cnt; i++) { int u=poi[i],ff=sett.fa[u]; if(ff==1)dp[u]=1,top[u]=u; else { if(aux.query(rt[top[ff]],1,n,sett.pos[u]-sett.len[u]+sett.len[top[ff]],sett.pos[u]-1)) dp[u]=dp[ff]+1,top[u]=u,ans=max(ans,dp[u]); else dp[u]=dp[ff],top[u]=top[ff]; } } printf("%d ",ans); } //syktxdy //qy dashenxian //chc duliu
  • 相关阅读:
    Idea中Module is not specified解决办法
    Navicat 导入数据时报Incorrect datetime value: '0000-00-00 00:00:00.000000' 错误
    SQL Server错误18456,window身份验证登录失败解决办法
    Linq
    web.config配置数据库连接
    $.ajax()方法详解
    将一张图片上传到指定的文件夹,然后在窗体上的PictrueBox控件中显示出来
    winform中picturebox自适应图片大小
    C#中产生SQL语句的几种方式
    [转]ORACLE触发器详解
  • 原文地址:https://www.cnblogs.com/stepsys/p/10708983.html
Copyright © 2020-2023  润新知