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


    题目的含义是将一个字符串的所有后缀按算出来的B函数从小到大按字典序排序

    首先观察到题目给定的只有ab两个字符,并且b函数给的是与当前位置之前的最近的相同的字符的位置差值

    首先暴力的思想就是对每个后缀算一遍b函数,但是发现这样是超时的,因此考虑能否进行优化

    我们观察到B函数会变化的原因是,我们求到某个后缀时,前面的数字是不存在的,因此当前位需要重0开始算

    但是一旦后缀中出现过a和b这两个字符,这样的话,这个后缀往后的b函数就和初始字符串是一样的。

    因此我们想到,如果可以分两部分进行排序,就可以解决问题,因为后一部分只需要求一次即可。

    而前一部分,只可能包含类似aaaab,bbba这种,当两种字符都出现过就到了第二部分

    而这种类似的字符串的b函数就是01110,这样两个0之间包含很多1。只需要比长度即可,而后半部分用后缀数组求一下rk值即可

    当然有些特殊情况,例如字符串后缀是bbbb这样只出现一种字符,我们只需要在n+1的位置补一下a就行,这并不影响原先的排名。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=2e6+10;
    int od[N],rk[N],id[N],cnt[N],sa[N],px[N];
    char s[N];
    int b[N];
    struct node{
        int x,y;
        bool operator <(const node &a) const{
            if(y-x==a.y-a.x){
                return rk[y+1]<rk[a.y+1];
            }
            return y-x<a.y-a.x;
        }
    }res[N];
    bool cmp(int x,int y,int w){
        return od[x]==od[y]&&od[x+w]==od[y+w];
    }
    void da(int *s,int n,int m){
        int i;
        for(i=1;i<=n;i++) cnt[i]=0;
        for(i=1;i<=n;i++) cnt[rk[i]=s[i]]++;
        for(i=1;i<=m;i++) cnt[i]+=cnt[i-1];
        for(i=n;i>=1;i--) sa[cnt[rk[i]]--]=i;
        int p;
        for(int w=1;w<n;w<<=1,m=p){
            p=0;
            for(i=n;i>n-w;i--)
                id[++p]=i;
            for(i=1;i<=n;i++)
                if(sa[i]>w)
                    id[++p]=sa[i]-w;
            for(i=1;i<=n;i++) cnt[i]=0;
            for(i=1;i<=n;i++) cnt[px[i]=rk[id[i]]]++;
            for(i=1;i<=m;i++) cnt[i]+=cnt[i-1];
            for(i=n;i>=1;i--) sa[cnt[px[i]]--]=id[i];
            for(i=0;i<=n;i++) od[i]=rk[i];
            for(p=0,i=1;i<=n;i++){
                rk[sa[i]]=cmp(sa[i-1],sa[i],w)?p:++p;
            }
        }
    }
    int main(){
        int n;
        ios::sync_with_stdio(false);
        while(cin>>n){
            cin>>s+1;
            int x=-1;
            int y=-1;
            int i;
            for(i=1;i<=n;i++){
                b[i]=0;
                if(s[i]=='a'){
                    if(x!=-1)
                        b[i]=i-x;
                    x=i;
                }
                else{
                    if(y!=-1)
                        b[i]=i-y;
                    y=i;
                }
            }
            da(b,n,n);
            x=n+1,y=n+1;
            for(i=n;i>=1;i--){
                if(s[i]=='a'){
                    res[i]={i,y};
                    x=i;
                }
                else{
                    res[i]={i,x};
                    y=i;
                }
            }
            rk[n+1]=-1;
            rk[n+2]=-2;
            sort(res+1,res+1+n);
            for(i=1;i<=n;i++){
                cout<<res[i].x<<" ";
            }
            cout<<endl;
        }
    }
    View Code
  • 相关阅读:
    send和sendmsg性能测试【sendmsg和send的性能基本一样,并没有得到优化】
    send和sendmsg性能测试
    SparkException: Master removed our application
    大数据入门:各种大数据技术介绍
    78 subsets
    C、C ++的内存模型
    将博客搬至CSDN
    适配器模式
    建造者(Builder)模式
    桥接模式
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/13305378.html
Copyright © 2020-2023  润新知