• luogu P5329 [SNOI2019]字符串


    传送门

    显然要写一个排序,那只要考虑cmp函数怎么写就行了.第(i)个字符串和第
    (j)个,首先前(min(i,j)-1)个字符是相同的,然后就是要比较后缀(min(i,j))(min(i,j)+1),先求lcp(要对(max(i,j)-min(i,j))(min)),如果两个后缀往后跳lcp的位置字符不一样就可以得到结果了.

    然后可以用SA求lcp 然后我T了,但是可以发现所有lcp都是相邻两个后缀的,所以这个可以(O(n))递推

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<vector>
    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<map>
    #include<set>
    #define LL long long
    #define db double
    
    using namespace std;
    const int N=2e6+10;
    int rd()
    {
        int x=0,w=1;char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
        return x*w;
    }
    
    char cc[N];
    int /*sa[N],rk[N],wr[N],wx[N],bk[N],*/he[N]/*,mi[N][21],L2[N]*/,n,an[N];
    /*void inii()
    {
        int sz=128,p=0,j=1;
        for(int i=1;i<=n;++i) ++bk[rk[i]=cc[i]];
        for(int i=1;i<=sz;++i) bk[i]+=bk[i-1];
        for(int i=n;i;--i) sa[bk[rk[i]]--]=i;
        while(p<n)
        {
            int tp=0;
            for(int i=n-j+1;i<=n;++i) wx[++tp]=i;
            for(int i=1;i<=n;++i) if(sa[i]>j) wx[++tp]=sa[i]-j;
            for(int i=1;i<=n;++i) wr[i]=rk[wx[i]];
            for(int i=1;i<=sz;++i) bk[i]=0;
            for(int i=1;i<=n;++i) ++bk[wr[i]];
            for(int i=1;i<=sz;++i) bk[i]+=bk[i-1];
            for(int i=n;i;--i) sa[bk[wr[i]]--]=wx[i];
            for(int i=1;i<=n;++i) wr[i]=rk[i];
            rk[sa[1]]=p=1;
            for(int i=2;i<=n;++i) rk[sa[i]]=p+=!(wr[sa[i]]==wr[sa[i-1]]&&wr[sa[i]+j]==wr[sa[i-1]+j]);
            sz=p,j<<=1;
        }
        for(int i=1;i<=n;++i)
        {
            if(he[rk[i-1]]) he[rk[i]]=he[rk[i-1]]-1;
            int j=sa[rk[i]-1];
            while(cc[i+he[rk[i]]]==cc[j+he[rk[i]]]) ++he[rk[i]];
        }
        for(int i=2;i<=n;++i) L2[i]=L2[i>>1]+1;
        for(int i=1;i<=n;++i) mi[i][0]=he[i];
        for(int j=1;j<=L2[n];++j)
            for(int i=1;i+(1<<j)-1<=n;++i)
                mi[i][j]=min(mi[i][j-1],mi[i+(1<<(j-1))][j-1]);
    }
    int lcp(int i,int j)
    {
        if(i==j) return n;
        i=rk[i],j=rk[j];
        if(i>j) swap(i,j);
        ++i;
        int z=L2[j-i+1];
        return min(mi[i][z],mi[j-(1<<z)+1][z]);
        }*/
    bool cmp(int i,int j)
    {
        /*int ii,jj;
        if(i<j) ii=i+1,jj=i;
        else ii=j,jj=j+1;
        int len=lcp(ii,jj);
        if(ii<i) len=min(len,i-ii);
        if(jj<j) len=min(len,j-jj);
        ii+=len,jj+=len;
        ii+=ii==i,jj+=jj==j;
        if(cc[ii]!=cc[jj]) return cc[ii]<cc[jj];
        return i<j;*/
        int ii=min(i,j),lm=max(i,j)-ii,len=he[ii+1];
        if(len>=lm) return i<j;
        return (cc[ii+len]<cc[ii+1+len])^(i<j);
    }
    
    int main()
    {
        n=rd();
        scanf("%s",cc+1);
        for(int i=2;i<=n;++i)
        {
            if(he[i-1]) he[i]=he[i-1]-1;
            while(cc[i+he[i]]==cc[i-1+he[i]]) ++he[i];
        }
        for(int i=1;i<=n;++i) an[i]=i;
        sort(an+1,an+n+1,cmp);
        for(int i=1;i<=n;++i) printf("%d ",an[i]);
        return 0;
    }
    
  • 相关阅读:
    入门指引之永久素材
    入门指引之上传临时素材
    入门指引之查看accesstoken
    java中的左移 右移
    病狗问题
    leetcode 几何题 位运算 面试编程
    CNN网络参数
    python学习整理
    JAVA问题整理
    计算机网络整理
  • 原文地址:https://www.cnblogs.com/smyjr/p/10801952.html
Copyright © 2020-2023  润新知