题意:将字符串s的每个后缀化成B数组,然后对B数组进行字典序排序。
题解:
网友提醒后补充一下:对于
这个的A应该是
,D为空,具体的分割的原则有两个一是D不会因为分割受到影响(第一个a和第一个b会变成0嘛,才能直接根据整个串的B数组的后缀数组rank值来排D)且D必须大于1开头,这样子A的影响才能绝对大于D的影响,第二个是A一定要以0开头,以0结尾,中间为1,如果后缀中没有‘a’’或’b’就在末尾补一个,容易想到这样并不会影响排名的结果(简单理解一下,如果都是没有b或a的,如0111,011,01那么都会长度加一,而不需要长度加一的部分,如果长度与其相同,如0110与0111长度相同,但0111>0110而这跟0111变成01110后01110>0110是一样的),且能实现根据A的长度来对A排序
正文:、
对于特定的后缀字符串
,其化成B数组的值时,第一个a的值为0,第一个b的值为0,在第一个a和第一个b之间的值为1。如
,则
,前半段为
。
这样,每个后缀子串就都有一个
,
其中
对于字典序排序,显然前半段的影响较大,那么将对A进行排序,再对A相同的D进行排序即可。
具体看一个例子;
给定字符串
(
先化成B数组:
,给其rk排名规定为-1
给其rk排名规定为-2
易知若
则
那么根据A来对
进行第一步排序,然后对相同的A的B进行根据D内部排序即可
对
排序直接看
的长度即可,长度越长
越大
而求A的长度,只需要求第一个
与第一个
的位置就可以知道了,这可以用滑动窗口O(n)时间内求得
观察
序列,如果我们队整个字符串求
值,那么显然D值与
相同长度的的后缀是一样的,则对
做一次求后缀数组得
值后,则
的排名了。
而这可以直接sort一下就行了。
代码:
#include <bits/stdc++.h>
using namespace std;
struct _IO{_IO(){ios::sync_with_stdio(0);cin.tie(0);}}_io;
typedef long long ll; typedef long double db;
const int N = 2e6 + 5, M = 1e9 + 7;
int sa[N], rk[N], oldrk[N << 1], id[N], px[N], cnt[N];
// px[i] = rk[id[i]](用于排序的数组所以叫 px)
bool cmp(int x, int y, int w) {
return oldrk[x] == oldrk[y] && oldrk[x + w] == oldrk[y + w];
}
void da(int *s, int n, int m) {
int i,p,w;
for(int i=0;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;
for (w = 1; w < n; w <<= 1, m = p) { // m=p 就是优化计数排序值域
for (p = 0, i = n; i > n - w; --i) id[++p] = i;
for (i = 1; i <= n; ++i)
if (sa[i] > w) id[++p] = sa[i] - w;
//memset(cnt, 0, sizeof(cnt));
for(int i=0;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(int i=0;i<=n;i++)oldrk[i]=rk[i];
//memcpy(oldrk, rk, sizeof(rk));
for (p = 0, i = 1; i <= n; ++i)
rk[sa[i]] = cmp(sa[i], sa[i - 1], w) ? p : ++p;
}
}
int n;
struct node {
int x, y;
bool operator < (const node &b) const {
if (y - x == b.y - b.x) {
return rk[y+1] < rk[b.y+1];
}
return y - x < b.y - b.x;
}
} a[N];
int b[N];
char s[N];
int main() {
while (cin >> n) {
cin >> 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 (y != -1) b[i] = i - y;
y = i;
}
}
for(int i=1;i<=n;i++)
{
b[i]++;
}
da(b, n, n);//后缀数组求出rank数组
for(int i=1;i<=n;i++)
x = y = n+1;
for (int i = n ; i >= 1; i--) {
if (s[i] == 'a') {
a[i] = {i, y};
x = i;
} else {
a[i] = {i, x};
y = i;
}
}
rk[n+1] = -1;
rk[n+2] = -2;
sort(a+1, a + n+1);
for (int i = 1; i <=n; i++) {
cout << a[i].x << ' ';
}
cout << '\n';
}
}