• 洛谷 P5108 仰望半月的夜空 解题报告


    P5108 仰望半月的夜空

    题目描述

    半月的夜空中,寄托了多少人与人之间的思念啊

    曦月知道,这些思念会汇集成一个字符串(S(n = |S|))

    由于思念汇集的过于复杂,因此曦月希望提炼出所有的思念

    我们定义(Y_S(i))表示对于字符串(S)而言,长度为(i)的子串中,字典序最小的,左端点最小的左端点的值

    比如对于串(S = "baa")(Y_S(1) = 2), (Y_S(2) = 2), (Y_S(3) = 1)

    曦月会告知你(S)串,你只需要告诉曦月(Y_S(i)(1 le i le n))即可

    输入输出格式

    输入格式:

    第一行,两个参数,分别是(sigma in {10, 26, 10^7})(n)

    如果(sigma = 26),那么第二行将是一个长为(n)的小写字母字符串(S)

    其他情况下,第二行将输入(n)个位于([0, sigma])内的整数

    输出格式:

    输出一行,第(i)个数表示(Y_S(i))的值

    说明

    (nle 300000)


    先考虑维护字典序最小。

    首先后缀排序求一下(sa)什么的

    然后拿一个指针扫描(sa)并把长度从小到大枚举,发现(sa)指针的移动是单调增的。

    但是当前字典序最小可能不在当前点,考虑到从当前点到可以成为答案的点的区间的lcp长度需要大于(L),所以我们可以进行二分找到这个右端点。

    然后再拿个什么维护一下这个区间内的最下左端点就可以了。

    复杂度(O(nlog n))


    Code:

    #include <cstdio>
    #include <algorithm>
    const int N=3e5+10;
    int tax[N],Rank[N],sa[N],sec[N],h[N],hei[N],lcp[20][N],st[20][N],Log[N];
    int typ,n,m,a[N],b[N];char s[N];
    void Rsort()
    {
        for(int i=1;i<=m;i++) tax[i]=0;
        for(int i=1;i<=n;i++) ++tax[Rank[i]];
        for(int i=1;i<=m;i++) tax[i]+=tax[i-1];
        for(int i=n;i;i--) sa[tax[Rank[sec[i]]]--]=sec[i];
    }
    bool cmp(int x,int y,int l){return sec[x]==sec[y]&&sec[x+l]==sec[y+l];}
    void SuffixSort()
    {
        for(int i=1;i<=n;i++) Rank[i]=a[i],sec[i]=i;
        Rsort();
        for(int p=0,w=1;p<n;w<<=1,m=p)
        {
            p=0;for(int i=n-w+1;i<=n;i++) sec[++p]=i;
            for(int i=1;i<=n;i++) if(sa[i]>w) sec[++p]=sa[i]-w;
            Rsort(),std::swap(Rank,sec),Rank[sa[p=1]]=1;
            for(int i=2;i<=n;i++) Rank[sa[i]]=cmp(sa[i],sa[i-1],w)?p:++p;
        }
        for(int k,i=1;i<=n;i++)
            for(k=sa[Rank[i]-1],h[i]=h[i-1]?h[i-1]-1:0;a[i+h[i]]==a[k+h[i]];++h[i]);
        Log[0]=-1;
        for(int i=1;i<=n;i++)
        {
            Log[i]=Log[i>>1]+1;
            st[0][i]=lcp[0][i]=i;
            hei[Rank[i]]=h[i];
        }
        for(int j=1;j<=19;j++)
        {
            for(int i=1;i<=n-(1<<j)+1;i++)
            {
                int x=st[j-1][i],y=st[j-1][i+(1<<j-1)];
                st[j][i]=sa[x]<sa[y]?x:y;
                x=lcp[j-1][i],y=lcp[j-1][i+(1<<j-1)];
                lcp[j][i]=hei[x]<hei[y]?x:y;
            }
        }
    }
    int qryLCP(int l,int r)
    {
        int d=Log[r+1-l],x=lcp[d][l],y=lcp[d][r-(1<<d)+1];
        return hei[x]<hei[y]?hei[x]:hei[y];
    }
    int qrypos(int l,int r)
    {
        int d=Log[r+1-l],x=st[d][l],y=st[d][r-(1<<d)+1];
        return sa[x]<sa[y]?sa[x]:sa[y];
    }
    int main()
    {
        scanf("%d%d",&typ,&n);
        if(typ==26)
        {
            scanf("%s",s+1);
            for(int i=1;i<=n;i++) a[i]=b[i]=s[i];
        }
        else
            for(int i=1;i<=n;i++) scanf("%d",a+i),b[i]=a[i];
        std::sort(b+1,b+1+n);
        m=std::unique(b+1,b+1+n)-b-1;
        for(int i=1;i<=n;i++) a[i]=std::lower_bound(b+1,b+1+m,a[i])-b;
        SuffixSort();
        int p=1;
        for(int i=1;i<=n;i++)
        {
            while(sa[p]+i-1>n) ++p;
            if(hei[p+1]<i)
            {
                printf("%d ",sa[p]);
                continue;
            }
            int l=p+1,r=n;
            while(l<r)
            {
                int mid=l+r+1>>1;
                if(qryLCP(p+1,mid)>=i) l=mid;
                else r=mid-1;
            }
            printf("%d ",qrypos(p,l));
        }
        return 0;
    }
    

    2019.1.1

  • 相关阅读:
    ASP.NET AJAX 's UpdatePanel 中使用Page.ClientScript.RegisterStartupScript 失败
    从struct到byte[]之RawFormatter
    一个HTTP.二进制POST和HTTP指定长度接收的C++实现
    发现移动太NB了,验证码图像路径直接包含验证码
    又一个网页下载者木马
    Trojan program TrojanDownloader.JS.IstBar.ai 病毒样本
    用控件的方式解决问题在客户端关联WEB控件引用
    需要防范的XSS攻击
    用"指定字符组成的任意进制"转换生成不带4的卡号
    人为漏洞的构造、文件的载入、验证机制的突破
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10205094.html
Copyright © 2020-2023  润新知