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?'\n':' ');
        for(int i=1;i<=n;i++) c[i]=x[i]=y[i]=0;
    }
    return 0;
}
/*
10
abbaababaa
*/
View Code

 

posted @ 2020-10-14 21:08  DeepJay  阅读(147)  评论(0)    收藏  举报