• 2020牛客多校第一场 B-Suffix Array (后缀数组)


    题目链接:传送门

    题目思路:传送门

         排序时,以A段长度l为第一关键字 ,以rk[i+l] 即 B段的rank 为第二关键字

         但是依然不对,这里有一个非常精妙的处理;

         对于A段来说,是0开头和0结尾,但是 aa ->01 , aaa->011 , a->0

         对于 01(A段长度为2)显然 是小于001(长度为2) ,但是01的长度现在确实2? 因此为了维护A的整体性质(0开头,0结尾),我们对于01...1 这类的字符串在后面补一个0,这样的话 01[0](长度为3,方括号是补充的0)显然就小于001(长度为2),01[0] 的B段是不存在的,那么可以假定B段存在且rank 可以设为一个更小的值; 但是对于 abbaaab 来说  后缀ab -> 00 , 后缀 b -> 0[0] ,显然 0[0] < 00 因此可以设置rk[n+1]=0 , rk[n+2]=-1,这样的话就能解决这个情况。

    #include<bits/stdc++.h>
    #include<cstdio>
    #include<cstring>
    #include<ctype.h>
    #include<functional>
    #include<algorithm>
    #pragma GCC optimize(2)
    using namespace std;
    std::mt19937 rnd(233);
    typedef long long LL;
    typedef pair<int,int> pii;
    typedef pair<LL,LL> pLL;
    #define pb push_back
    #define mk make_pair
    #define fi first
    #define se second
    #define ls (i<<1)
    #define rs (i<<1|1)
    #define mem(a,b) memset(a,b,sizeof(a))
    const int N=1e6+5;
    const int inf=0x3f3f3f3f;
    const LL mod=1e9+7;
    LL read()
    {
        LL x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); }
        while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); }
        return f*x;
    }
    int sa[N],rk[N],x[N],y[N],c[N],he[N],n,m;
    struct node { int l,r,id; }a[N];
    bool cmp(node p,node q)
    {
        return p.l==q.l?p.r<q.r:p.l<q.l;
    }
    char t[N];
    int s[N];
    void SA()
    {
        m=n;
        for(int i=1;i<=m;i++) c[i]=0;
        for(int i=1;i<=n;i++) c[x[i]=s[i]]++;
        for(int i=1;i<=m;i++) c[i]+=c[i-1];
        for(int i=n;i;i--) sa[c[x[i]]--]=i;
        for(int k=1;k<=n;k<<=1)
        {
            int tot=0;
            for(int i=n-k+1;i<=n;i++) y[++tot]=i;
            for(int i=1;i<=n;i++) if(sa[i]>k) y[++tot]=sa[i]-k;
            for(int i=1;i<=m;i++) c[i]=0;
            for(int i=1;i<=n;i++) c[x[i]]++;
            for(int i=1;i<=m;i++) c[i]+=c[i-1];
            for(int i=n;i;i--) sa[c[x[y[i]]]--]=y[i];
            for(int i=1;i<=n;i++) y[i]=x[i];
            x[sa[1]]=tot=1;
            for(int i=2;i<=n;i++)
                x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?tot:++tot);
            if(tot==n) break;
            m=tot;
        }
        for(int i=1;i<=n;i++) rk[sa[i]]=i;
    }
    int main()
    {
        while(scanf("%d",&n)!=EOF)
        {
            scanf("%s",t+1);
            int pa=0,pb=0;
            for(int i=1;i<=n;i++)
            {
                if(t[i]=='a')
                {
                    if(pa) s[i]=i-pa+1;
                    else s[i]=1;
                    pa=i;
                }
                else
                {
                    if(pb) s[i]=i-pb+1;
                    else s[i]=1;
                    pb=i;
                }
            }
            SA();
            pa=pb=0;
            rk[n+1]=0,rk[n+2]=-1;
            for(int i=n;i;i--)
            {
                if(t[i]=='a') pa=i;
                else pb=i;
                if(!pa||!pb)
                {
                    a[i].l=n-i+2;
                }
                else a[i].l=abs(pa-pb)+1;
                a[i].id=i;
                a[i].r=rk[i+a[i].l];
            }
            sort(a+1,a+n+1,cmp);
            for(int i=1;i<=n;i++) printf("%d%c",a[i].id,i==n?'
    ':' ');
            for(int i=1;i<=n;i++) c[i]=x[i]=y[i]=0;
        }
        return 0;
    }
    /*
    10
    abbaababaa
    */
    View Code
  • 相关阅读:
    SQL Server 动态行转列(参数化表名、分组列、行转列字段、字段值)
    Web Api 跨域解决方案
    Web Api Session开启会话支持
    Web Service 学习
    省市选择器
    如何创建圆形头像和圆角图片
    E
    二叉树
    素数筛法
    Color Me Less
  • 原文地址:https://www.cnblogs.com/DeepJay/p/13817388.html
Copyright © 2020-2023  润新知