题目连接
题意:
给你一个长度为
n
n
n的只由‘a’和‘b’组成字符串
(
n
<
=
1
e
5
)
(n <= 1e5)
(n<=1e5),并重新定义了这个字符串的所有后缀的串的值,让你出去重新定义完以后的该字符串的所有后缀的sa,定义如下:当前位置的值为与前一次出现相同字符的位置的距离。
分析:
举个例子,比如
a
a
b
a
a
b
a
a
a
b
a
aabaabaaaba
aabaabaaaba,那么这个字符串的后缀和所对应的值为:
a
a
b
a
a
b
a
a
a
b
a
01021321142
a
b
a
a
b
a
a
a
b
a
0021321142
b
a
a
b
a
a
a
b
a
001321142
a
a
b
a
a
a
b
a
01021142
a
b
a
a
a
b
a
0021142
b
a
a
a
b
a
001142
a
a
a
b
a
01102
a
a
b
a
0102
a
b
a
002
b
a
00
a
0
aabaabaaaba \qquad \qquad 01021321142 \\abaabaaaba \qquad \qquad \ \ 0021321142 \\baabaaaba \qquad \qquad \quad 001321142 \\aabaaaba \qquad \qquad \quad \ \ 01021142 \\abaaaba \qquad \qquad \quad \quad0021142 \\baaaba\qquad \qquad \quad \quad \ \ 001142 \\aaaba\qquad \qquad \quad \quad \quad 01102 \\aaba \qquad \qquad\qquad\quad \ \ 0102 \\aba\qquad \qquad\qquad \qquad002 \\ba \qquad \qquad\qquad \qquad \ \ 00 \\a \qquad \qquad\qquad \qquad \quad 0
aabaabaaaba01021321142abaabaaaba 0021321142baabaaaba001321142aabaaaba 01021142abaaaba0021142baaaba 001142aaaba01102aaba 0102aba002ba 00a0
乍一看啥都没看出来,比赛的时候也对这个分析了半天一无所获。看了题解才理解,太妙了。
首先对这一串数字进行分组,第一组是该字符串从左到右直到a,b都出现过一次就停止。即出现两个0
那么上面的就是
010
,
00
,
00
,
010
,
00
,
00
,
0110
,
010
,
00
,
00
,
0
010,00,00,010,00,00,0110,010,00,00,0
010,00,00,010,00,00,0110,010,00,00,0
然后你会发现一个神奇的事情就是,字符串越长,这个字符的字典序就越大!那么第一部分就解决了。
第二组就是剩下的组合,那么就是:
21321142
,
21321142
,
1321142
,
21142
,
1142
,
42
,
2
,
2
,
2
,
n
u
l
l
,
n
u
l
l
21321142,21321142,1321142,21142,1142,42,2,2,2,null,null
21321142,21321142,1321142,21142,1142,42,2,2,2,null,null
然后就可以发现这些都是原始字符串的第
n
−
l
e
n
+
1
n-len+1
n−len+1个后缀,因此我们对原始数组求一次sa即可得到后面一部分字符串的rk。
于是对原字符串的排序就说一个简单的比较了,先按第一关键字小的,相同就按第二关键字小的,然后输出就好了。
代码:
#include<bits/stdc++.h>
#define mes(a, b) memset(a, b, sizeof a)
#define pb push_back
typedef unsigned long long int ull;
typedef long long int ll;
const int maxn = 1e5 + 20;
const int maxm = 1e5 + 10;
const ll mod = 1e9 + 7;
const ll INF = 1e18 + 100;
const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-8;
using namespace std;
char s[maxn];
int b[maxn];
int rk[maxn],tp[maxn],sa[maxn],tax[maxn];
int n,m;
void Qsort(){
for(int i = 0;i <= m;i++) tax[i] = 0;
for(int i = 1;i <= n;i++) tax[rk[i]]++;
for(int i = 1;i <= m;i++) tax[i] += tax[i -1];
for(int i = n;i >= 1;i--) sa[tax[rk[tp[i]]]--] = tp[i];
}
void GetSa(){
m = n;
for(int i = 1;i <= n;i++) tp[i] = i,rk[i] = b[i];
Qsort();
int p = 0;
for(int w = 1;p < n;w <<= 1){
int tot = 0;
for(int i = 1;i <= w;i++) tp[++tot] = n - w + i;
for(int i = 1;i <= n;i++) if(sa[i] > w) tp[++tot] = sa[i] - w;
Qsort();
for(int i = 1;i <= n;i++) tp[i] = rk[i];
rk[sa[1]] = p = 1;
for(int i = 2;i <= n;i++){
rk[sa[i]] = (tp[sa[i - 1]] == tp[sa[i]] && tp[sa[i - 1] + w] == tp[sa[i] + w]) ? p : ++p;
}
m = p;
}
}
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;
}
}a[maxn];
int main(){
while(~scanf("%d",&n)){
scanf("%s",s + 1);
int x = -1,y = -1;
for(int i = 1;i <= n;i++){
b[i] = 0;
if(s[i] == 'a'){
if(x != -1) b[i] = i - x;
x = i;
}
else if(s[i] == 'b'){
if(y != -1) b[i] = i - y;
y = i;
}
b[i]++;
}
GetSa();
rk[n + 2] = -2;
rk[n + 1] = -1;
x = y = n + 1;
for(int i = n;i >= 1;i--){
if(s[i] == 'a'){
a[i] = {i,y};x = i;
}
else if(s[i] == 'b'){
a[i] = {i,x};y = i;
}
}
sort(a + 1,a + 1 + n);
for(int i = 1;i <= n;i++) printf("%d ",a[i].x);
puts("");
}
}