• [bzoj3998][TJOI2015]弦论


    后缀自动机丝薄题。

    求给定字符串$s$的第$k$大的子串。分unique之后的和不unique的两种询问。


    首先构建出SAM。

    相同子串算一个的情况:

    SAM上所有路径组成字符串$s$的全部子串,每个状态向下不管怎么走,形成的串都是以当前状态为前缀的。(废话)

    所以我们只要知道以当前串为前缀的串有多少,不就可以像在平衡树上搜索一样找到第$k$大吗。

    即从当前点开始,向下有多少路径。拓扑跑一下就行了。$sum[u]=sum sum[v] +1$。

    另一种情况:

    思路和第一种完全一样,区别在于所在位置不同的相同子串本质不同了。我们发现$right$集合的大小不就是当前状态的有多少个吗。所以我们先求出每个点$u$的$right$集合有多大($u$的$right$集合就是所有以$u$为$parent$(也有叫$link$,我叫$fa$)的点的$right$集合的并集呀),一个道理,拓扑跑一下。$sum[u]=sum sum[v]+|right(u)|$

    代码可以简化的地方很多。。

    看大佬们的代码都不用dfs去统计,蒟蒻想了半天发现自己傻掉了。因为我们知道不管在SAM的DAG中,还是在$parent$树中,儿子的$len$($max$?就是丽洁神犇ppt里的$max$)都比父亲大(DAG上说父子的话不太严密,但意思就是那样)。于是按$len$排序(注意可以基数排序!)然后再转移就一定不会错啦。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1000010;
    typedef long long ll;
    int len[N],fa[N],ch[N][26];
    int las,sz;
    int opt,n,val[N],sum[N],v[N],q[N];
    void ins(int c){
        int now=++sz;len[now]=len[las]+1;
        int p,q;val[now]=1;
        for(p=las;~p&&!ch[p][c];p=fa[p])
        ch[p][c]=now;
        if(!~p)fa[now]=0;
        else{
            q=ch[p][c];
            if(len[q]==len[p]+1)
                fa[now]=q;
            else{
                int r=++sz;
                fa[r]=fa[q],len[r]=len[p]+1;
                for(int i=0;i<26;i++)
                ch[r][i]=ch[q][i];
                for(;~p&&ch[p][c]==q;p=fa[p])
                ch[p][c]=r;
                fa[now]=fa[q]=r;
            }
        }
        las=now;
    }
    void init(){
        for(int i=0;i<=sz;i++)v[len[i]]++;
        for(int i=1;i<=n;i++)v[i]+=v[i-1];
        for(int i=sz;~i;i--)
        q[v[len[i]]--]=i;
        for(int i=sz+1;i;i--){
            int t=q[i];
            if(opt==1)val[fa[t]]+=val[t];
            else val[t]=1;
        }
        val[0]=0;
        for(int i=sz+1;i;i--){
            int t=q[i];sum[t]=val[t];
            for(int j=0;j<26;j++)
            sum[t]+=sum[ch[t][j]];
        }
    }
    void dfs(int u,int rk){
        if(rk<=val[u])return;
        rk-=val[u];
        for(int i=0;i<26;i++)
        if(ch[u][i]){
            int t=ch[u][i];
            if(rk<=sum[t]){
                putchar(i+'a');
                dfs(t,rk);
                return;
            }
            rk-=sum[t];
        }
    }
    void solve(){
        init();
        int k;scanf("%d",&k);
        dfs(0,k);
    }
    char s[N];
    int main(){
        scanf("%s",s);fa[0]=-1;
        n=strlen(s);
        for(int i=0;i<n;i++)
        ins(s[i]-'a');
        scanf("%d",&opt);
        solve();
    }

     

  • 相关阅读:
    Analysis Services features supported by SQL Server editions
    Azure DevOps to Azure AppServices
    Power BI For Competition
    Win10开机“提示语音”以及”随机播放音乐”
    Azure DevOps
    Allow Only Ajax Requests For An Action In ASP.NET Core
    Mobile CI/CD 101
    Configure SSL for SharePoint 2013
    AWS Step Function Serverless Applications
    Cordova Upload Images using File Transfer Plugin and .Net core WebAPI
  • 原文地址:https://www.cnblogs.com/orzzz/p/8306726.html
Copyright © 2020-2023  润新知