zoukankan      html  css  js  c++  java
  • P3975 [TJOI2015]弦论 (SAM)

    题目链接

    https://www.luogu.com.cn/problem/P3975

    题意

    给你一个仅由小写字母构成的字符串(s),输出它的第(k)小子串((t=0)时表示不同位置的相同子串算作一个,(t=1)时表示不同位置的相同子串算作多个)

    思路

    构建出SAM之后,求出(sum[i]),表示有(sum[i])个子串经过(i)号点。
    (siz[i])表示(i)所代表的(endpos)的集合大小,也就是(i)所对应字符串集合的出现次数。
    (t=0)时,本质相同的子串在不同位置出现算相同,所以(siz[i]=1),即将每个字符串集合的(endpos)集合大小(字符串集合元素出现次数)置为(1)
    (t=1)时,本质相同的子串在不同位置出现算不同,那么累加后的(siz)表示实际上(endpos)的集合大小
    在SAM的树结构上(dp)(siz)
    在SAM的图结构上(dp)(sum)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int maxx = 2*1e6+10;
    char s[maxx];
    int last=1,tot=1,fa[maxx],ch[maxx][26],len[maxx];
    LL siz[maxx],sum[maxx];
    void add(int x)
    {
        int pre=last,now=last=++tot;
        len[now]=len[pre]+1;siz[now]=1;
        for(;pre&&!ch[pre][x];pre=fa[pre])ch[pre][x]=now;
        if(!pre)fa[now]=1;
        else
        {
            int q=ch[pre][x];
            if(len[q]==len[pre]+1)fa[now]=q;
            else
            {
                int nows=++tot;
                len[nows]=len[pre]+1;
                memcpy(ch[nows],ch[q],sizeof(ch[q]));
                fa[nows]=fa[q];fa[q]=fa[now]=nows;
                for(;pre&&ch[pre][x]==q;pre=fa[pre])ch[pre][x]=nows;
            }
        }
    }
    
    int head[maxx],to[maxx],ne[maxx],cnt;
    int vis[maxx];
    void addm(int u,int v)
    {
        to[++cnt]=v,ne[cnt]=head[u],head[u]=cnt;
    }
    void dfs1(int u)
    {
        for(int i=head[u];i;i=ne[i])
        {
            dfs1(to[i]);
            siz[u]+=siz[to[i]];
        }
    }
    void dfs2(int u)
    {
        if(vis[u])return;
        vis[u]=1;
        for(int i=0;i<26;i++)
        {
            int v=ch[u][i];
            if(v)dfs2(v),sum[u]+=sum[v];
        }
    }
    void solve(int u,int k)
    {
        if(k<=siz[u])return;
        k-=siz[u];
        for(int i=0;i<26;i++)
        {
            int v=ch[u][i];
            if(!v)continue;
            if(k>sum[v])k-=sum[v];
            else
            {
                putchar(i+'a');
                solve(v,k);
                return;
            }
        }
    }
    int main()
    {
        scanf("%s",s+1);
        int t,k;
        scanf("%d%d",&t,&k);
        int n=strlen(s+1);
        for(int i=1;i<=n;i++)add(s[i]-'a');
        for(int i=2;i<=tot;i++)addm(fa[i],i);
        dfs1(1);
        for(int i=1;i<=tot;i++)
        {
            if(t)sum[i]=siz[i];
            else sum[i]=siz[i]=1;
        }
        sum[1]=siz[1]=0; //根的点权为0
        dfs2(1);
        if(sum[1]<k)puts("-1");
        else solve(1,k),puts("");
        return 0;
    }
    
  • 相关阅读:
    原型,原型对象,原型链,构造函数,继承(一)
    暑假闲着没事第一弹:基于Django的长江大学教务处成绩查询系统
    ANDROID自定义视图——onMeasure流程,MeasureSpec详解
    android 中发送短信
    VelocityTracker简介
    Android xml资源文件中@、@android:type、@*、?、@+含义和区别
    android:id="@+id/android:empty属性的用法举例
    Android ProgressBar详解以及自定义
    Android自定义进度条
    布局技巧:使用ViewStub
  • 原文地址:https://www.cnblogs.com/HooYing/p/12968410.html
Copyright © 2011-2022 走看看