[SNOI2019]字符串

Luogu5329

设删掉第\(i\)个字符之后得到的字符串为\(s_i\) , 请按照字典序对\(s_1,s_2,……,s_n\)从小到大排序。若两个字符串相等,则认为编号小的字符串字典序更小。

考虑删掉第\(i\)位和第\(j\)位,其首尾相等,所以只要考虑\(s[i+1,j]\)\(s[i,j-1]\)的大小就行了。

考虑写这样一个\(cmp\)函数,它的格式已经是固定了的,那么关键是需要预处理出某一段区间是相等的

\(f[i]\)表示\(i\)位置之后,第一个\(s[i]!=s[i+1]\)的位置

\(if(f[i]>=j)\) 中间串相等,编号小的在前
\(if(f[i]<j)\) 比较这第一个不相同的位置的大小

详见代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define Debug(x) cout<<#x<<"="<<x<<endl
#define rank Rank
using namespace std;
typedef long long LL;
const int INF=1e9+7;
inline LL read(){
    register LL x=0,f=1;register char c=getchar();
    while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
    while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
    return f*x;
}

const int N=1e6+5;

int same[N],rank[N],n;
char s[N];

inline bool cmp(int a,int b){
    if(a<b){
        if(same[a]>=b) return 1;
        return s[same[a]+1]<s[same[a]];
    }
    else return !cmp(b,a);//我觉得这样比较好,就固定了格式只有一种
    /*else{
        if(same[b]>=a) return 0;
        return s[same[b]]<s[same[b]+1];
    }*/
}

int main(){
    n=read();scanf("%s",(s+1));
    for(int i=1,t=1;i<=n;i++){
        if(t<i) t=i;
        while(t<n&&s[t]==s[t+1]) t++;
        same[i]=t;
    }
    for(int i=1;i<=n;i++) rank[i]=i;
    sort(rank+1,rank+n+1,cmp);
    for(int i=1;i<=n;i++) printf("%d ",rank[i]);
}

猜你喜欢

转载自www.cnblogs.com/lizehon/p/10804366.html