• 【学习笔记】CF1817F Entangled Substrings(基本子串结构)


    前置知识:基本子串结构,SAM的结构和应用

    学长博客

    字符串理论比较抽象,建议直观的去理解它

    子串 t t t的扩展串定义为 ext(t) : = t ′ \text{ext(t)}:=t' ext(t):=t,满足 t t t t ′ t' t的子串,且 occ(t) = occ(t’) \text{occ(t)}=\text{occ(t')} occ(t)=occ(t’)

    基本性质:若 t = [ l : r ] , t ′ = [ l ′ : r ′ ] t=[l:r],t'=[l':r'] t=[l:r],t=[l:r] t ′ ′ = [ l ′ ′ : r ′ ′ ] t''=[l'':r''] t′′=[l′′:r′′],使得 l ′ ≤ l ′ ′ ≤ l ≤ r ≤ r ′ ′ ≤ r ′ l'\le l''\le l\le r\le r''\le r' ll′′lrr′′r,则 ext(t”) = t ′ \text{ext(t'')}=t' ext(t”)=t

    子串 x , y x,y x,y等价当且仅当 ext(x) = ext(y) \text{ext(x)}=\text{ext(y)} ext(x)=ext(y)。然后,记录每个等价类的最长串作为代表元。

    s [ l : r ] ↦ ( l , r ) s[l:r]\mapsto (l,r) s[l:r](l,r)的作用下,在 y = x y=x y=x以上的点被等价类划分入若干个阶梯状集合,其中 g \text{g} g对应的阶梯 出现次数 occ(rep(g)) \text{occ(\text{rep(g)})} occ(rep(g))

    对于等价类 g g g个某个 完整阶梯,其完整的一行对应的子串集合与 T 0 T_0 T0的某个结点对应的子串集合相同,其完整的一列对应的子串集合与 T 1 T_1 T1(反串对应的后缀树)某个节点对应的子串集合相同,并且一一对应。

    定义等价类 g g g的周长为其 一个 完整阶梯的行数列数之和,性质: ∑ g per(g) = O ( n ) \sum_g\text{per(g)}=O(n) gper(g)=O(n)

    比较抽象。不是很直观。

    如何显式求出这个结构?

    第一种方式:对于 T 0 T_0 T0的从父亲到儿子的树边,其从一行的左边界指向另一行的右边界;对于 T 1 T_1 T1的从父亲到儿子的树边,其从一行的上边界连向另一行的下边界。

    例如, s = aababcd ‾ s=\underline{\text{aababcd}} s=aababcd,其对应的阶梯划分为:

    请添加图片描述
    其对应的 S A M SAM SAM T 0 T_0 T0为:

    请添加图片描述

    其对应的连边为:

    请添加图片描述

    第二种方式(感觉更常用):对于 D A G DAG DAG上的一条边 ( u , v ) (u,v) (u,v),如果 occ(u) = occ(v) \text{occ(u)}=\text{occ(v)} occ(u)=occ(v),那么就将这条边标记为关键边。

    性质:如果只保留关键边,那么每个点入度和出度都至多为一,因此我们得到了若干条关键链。显然,链的末尾就是代表元,一条链就代表了一个等价类

    考虑这道题目在让我们干什么:可以发现一个字符串对 ( b 1 , b 2 ) (b_1,b_2) (b1,b2)是好的当且仅当满足以下条件:

    1.1 1.1 1.1 b 1 , b 2 b_1,b_2 b1,b2在同一个等价类中
    1.2 1.2 1.2 b 1 , b 2 b_1,b_2 b1,b2所在等价类中的代表元为 b b b,那么 b 1 , b 2 b_1,b_2 b1,b2 b b b中出现的位置不交,且 b 1 b_1 b1 b 2 b_2 b2左边

    这样,我们对于每个 阶梯状物 统计答案即可。(建议数形结合,以及把下标搞清楚)

    代表元的 len \text{len} len实际上表示阶梯状物左上角那个位置的横纵坐标之差。

    复杂度 O ( n ) O(n) O(n)

    #include
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    using namespace std;
    const int N=2e5+5;
    struct node{
        int to[26],link,len,sz;
    }t[N];
    int n,cur,last,tot,sz[N];
    void extend(int ch){
        int cur=++tot;
        t[cur].len=t[last].len+1,t[cur].sz=1;
        int p=last;
        while(p!=-1&&!t[p].to[ch]){
            t[p].to[ch]=cur;
            p=t[p].link;
        }
        if(p!=-1){
            int q=t[p].to[ch];
            if(t[q].len==t[p].len+1){
                t[cur].link=q;
            }
            else{
                int clone=++tot;
                t[clone].link=t[q].link;
                for(int i=0;i<26;i++)t[clone].to[i]=t[q].to[i];
                t[clone].len=t[p].len+1;
                while(p!=-1&&t[p].to[ch]==q){
                    t[p].to[ch]=clone;
                    p=t[p].link;
                }
                t[q].link=t[cur].link=clone;
            }
        }
        last=cur;
    }
    string str;
    int nxt[N],vs[N];
    int st[N],cnt;
    ll s[N];
    ll res;
    vector<int>G[N];
    void dfs(int u){
        for(auto v:G[u])dfs(v),t[u].sz+=t[v].sz;
    }
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0),cout.tie(0);
        t[0].link=-1;cin>>str,n=str.size();
        for(int i=0;i<n;i++)extend(str[i]-'a');
        for(int i=1;i<=tot;i++)G[t[i].link].pb(i);
        dfs(0);
        for(int i=1;i<=tot;i++){
            for(int j=0;j<26;j++){
                int k=t[i].to[j];
                if(k&&t[i].sz==t[k].sz)nxt[i]=k,vs[k]=1;
            }
        }
        for(int i=1;i<=tot;i++){
            if(vs[i]==0){
                cnt=0;int e=0;
                for(int j=i;j;j=nxt[j])e=j,st[++cnt]=t[j].len-t[t[j].link].len;
                for(int j=1;j<=cnt;j++)s[j]=s[j-1]+st[j];
                int p=1,len=t[e].len;
                for(int j=len-cnt+1;j<=st[cnt]&&j<=len+1;j++){
                    while(p<=cnt&&st[p]<j)p++;
                    res+=s[cnt-len+j-1]*(cnt-p+1);
                }
            }
        }cout<<res;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
  • 相关阅读:
    (蓝桥杯C/C++)——常用库函数
    PGD(projected gradient descent)算法源码解析
    ROS中的坐标转换1
    【网络】详解HTTPS及探究加密过程
    【WSN定位】基于chan算法、fang算法、taylor算法实现目标定位附Matlab代码
    Unity学习——碰撞器
    tc260大数据安全标准化工作研究成果 学习笔记
    Npm的一些镜像地址-复制粘帖
    MySQL 操作语句大全(详细)
    1338:【例3-3】医院设置
  • 原文地址:https://blog.csdn.net/cqbzlydd/article/details/133413573