2020牛客暑期多校训练营(第一场)A. B-Suffix Array

链接

https://ac.nowcoder.com/acm/contest/5666/A

题意

对于字符串 $t_1t_2…t_k$

定义 $B(t_1t_2…t_k)=b_1b_2…b_k$

若存在 $t_j=t_i$ ($j<i$),那么 $b_i=\min_{1\le j<i,t_j=t_i}{i-j}$

否则 $b_i=0$

将字符串 $S$ (由 “a”,”b” 组成)的所有后缀按照其对应的 $B$ 序列的字典序排序

思路

对于字符串 $T$,可发现 $B(T)=AD,A=01..10$,可发现 $A$ 的长度越大,$A$ 的字典序越大

我们可以 $O(n)$ 求出 $B(s_1s_2…s_k)$ 所有的 $A$ 的长度,易发现 $B(s_1s_2…s_k)$ 的 $D$ 为 $B(S)$ 的后缀,用 $SA$ 求 $B(S)$ 后缀的排序,可以将 $A$ 作为第一关键字排序,$D$ 作为第二关键字排序

注意:

对于类似 ‘’aaa’’ 的情况,我们需要在最后加一个 ‘b’,此时 $A=0110$,否则 $A=011$,在 $A$ 长度相等情况下,$011$ 明显是大于 $010$ 的

在第二关键字排序时,$D$ 可能为空,下标为 $len+1,len+2$,分别将排名赋值为 $0,-1$ 即可

官方题解

设 $C_i = \min_{j > i,s_j = s_i} {j - i}$,数组 $C$ 的后缀从小到大排序就是答案

Detailed proof can be found in “Parameterized Suffix Arrays for Binary Strings ” http://www.stringology.org/event/2008/p08.html

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
char s[N];
int n,nxt[2],pre[2],a[N],b[N],res[N];
int m,p,sa[N],id[N],rk[N],oldrk[N<<1],cnt[N];
void init() {
for(int i=0;i<2;i++) nxt[i]=pre[i]=0;
memset(b,0,sizeof b);
for(int i=1;i<=n;i++) res[i]=i,a[i]=0;
}
void get_sa(int *s) {
m=300;
for(int i=1;i<=n;i++) cnt[i]=0;
for(int i=1;i<=n;i++) cnt[rk[i]=s[i]]++;
for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
for(int i=n;i>=1;i--) sa[cnt[rk[i]]--]=i;
for(int w=1,p;w<n;w<<=1,m=p) {
p=0;
for(int i=n;i>n-w;i--) id[++p]=i;
for(int i=1;i<=n;i++) if(sa[i]>w) id[++p]=sa[i]-w;
for(int i=1;i<=m;i++) cnt[i]=0;
for(int i=1;i<=n;i++) cnt[rk[id[i]]]++;
for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
for(int i=n;i>=1;i--) sa[cnt[rk[id[i]]]--]=id[i];
for(int i=1;i<=n;i++) oldrk[i]=rk[i];
p=0;
for(int i=1;i<=n;i++) rk[sa[i]]=((oldrk[sa[i]]==oldrk[sa[i-1]]&&oldrk[sa[i]+w]==oldrk[sa[i-1]+w])?p:++p);
}
}
bool cmp(int x,int y) {
return a[x]<a[y]||a[x]==a[y]&&rk[x+a[x]]<rk[y+a[y]];
}
int main() {
while(~scanf("%d",&n)) {
scanf("%s",s+1);
init();
for(int i=1;i<=n;i++) {
if(pre[s[i]-'a']) b[i]=i-pre[s[i]-'a'];
pre[s[i]-'a']=i;
}
for(int i=n;i>=1;i--) {
if(!nxt[(s[i]-'a')^1]) a[i]=n-i+2;
else a[i]=nxt[(s[i]-'a')^1]-i+1;
nxt[s[i]-'a']=i;
}
get_sa(b);
rk[n+1]=0;
rk[n+2]=-1;
sort(res+1,res+1+n,cmp);
for(int i=1;i<=n;i++) printf("%d ",res[i]);
puts("");
}
return 0;
}