「补档计划」后缀数组

后缀数组的一些应用和题目,这里所有的时间复杂度均针对 SA-IS 算法。

「SPOJ694」Distinct Substrings

链接

SPOJ694

题解

题意就是给定一个字符串,求该字符串含有的本质不同的子串数量。

由于每个子串都是某个后缀的前缀,我们可以统计每个后缀的数量,而排名第 $i$ 的后缀与排名第 $i - 1$ 的后缀有 $height[i]$ 个相同的前缀,所以从答案中减去这些。

即答案为

$$\sum_{i = 1}^{len(s)}(len(suffix(i - 1)) - height[i])$$

时间复杂度为 $O(n)$。

代码

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*******************************************************************************
* Copyright (c) 2016-2017, xehoth
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name xehoth, nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY XEHOTH AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL XEHOTH AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include <bits/stdc++.h>
/**
* 「SPOJ694」Distinct Substrings 24-05-2017
* 后缀数组
* @author xehoth
*/
namespace IO {

inline char read() {
static const int IN_LEN = 1000000;
static char buf[IN_LEN], *s, *t;
s == t ? t = (s = buf) + fread(buf, 1, IN_LEN, stdin) : 0;
return s == t ? -1 : *s++;
}

template<typename T>
inline void read(T &x) {
static char c;
static bool iosig;
for (c = read(), iosig = false; !isdigit(c); c = read()) {
if (c == -1) return;
c == '-' ? iosig = true : 0;
}
for (x = 0; isdigit(c); c = read())
x = (x + (x << 2) << 1) + (c ^ '0');
iosig ? x = -x : 0;
}

inline int read(char *buf) {
register int s = 0;
register char c;
while (c = read(), isspace(c) && c != -1);
if (c == -1) {
*buf = '\0';
return -1;
}
do buf[s++] = c; while (c = read(), !isspace(c) && c != -1);
buf[s] = '\0';
return s;
}

const int OUT_LEN = 1000000;

char obuf[OUT_LEN], *oh = obuf;

inline void print(char c) {
oh == obuf + OUT_LEN ? (fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf) : 0;
*oh++ = c;
}

template<typename T>
inline void print(T x) {
static int buf[30], cnt;
if (x == 0) {
print('0');
} else {
x < 0 ? (print('-'), x = -x) : 0;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 | 48;
while (cnt) print((char)buf[cnt--]);
}
}

inline void flush() {
fwrite(obuf, 1, oh - obuf, stdout);
}
}

namespace SuffixArray {

const int MAXN = 1005;

int sa[MAXN], rk[MAXN], ht[MAXN];
bool t[MAXN << 1];

inline bool islms(const int i, const bool *t) {
return i > 0 && t[i] && !t[i - 1];
}

template<typename T>
inline void sort(T s, int *sa, const int len, const int sz, const int sigma,
bool *t, int *b, int *cb, int *p) {
memset(b, 0, sizeof(int) * sigma);
memset(sa, -1, sizeof(int) * len);
for (register int i = 0; i < len; i++) b[s[i]]++;
cb[0] = b[0];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i];
for (register int i = sz - 1; i >= 0; i--) sa[--cb[s[p[i]]]] = p[i];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i - 1];
for (register int i = 0; i < len; i++) if (sa[i] > 0 && !t[sa[i] - 1])
sa[cb[s[sa[i] - 1]]++] = sa[i] - 1;
cb[0] = b[0];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i];
for (register int i = len - 1; i >= 0; i--) if (sa[i] > 0 && t[sa[i] - 1])
sa[--cb[s[sa[i] - 1]]] = sa[i] - 1;
}

template<typename T>
inline void sais(T s, int *sa, const int len, bool *t, int *b, int *b1,
const int sigma) {
register int i, j, x, p = -1, cnt = 0, sz = 0, *cb = b + sigma;
for (t[len - 1] = 1, i = len - 2; i >= 0; i--) t[i] = s[i] < s[i + 1] ||
(s[i] == s[i + 1] && t[i + 1]);
for (i = 1; i < len; i++) if (t[i] && !t[i - 1]) b1[sz++] = i;
sort(s, sa, len, sz, sigma, t, b, cb, b1);
for (i = sz = 0; i < len; i++) if (islms(sa[i], t)) sa[sz++] = sa[i];
for (i = sz; i < len; i++) sa[i] = -1;
for (i = 0; i < sz; i++) {
for (x = sa[i], j = 0; j < len; j++) {
if (p == -1 || s[x + j] != s[p + j] || t[x + j] != t[p + j]) {
p = x, cnt++;
break;
} else if (j > 0 && (islms(x + j, t) || islms(p + j, t))) {
break;
}
}
sa[sz + (x >>= 1)] = cnt - 1;
}
for (i = j = len - 1; i >= sz; i--) if (sa[i] >= 0) sa[j--] = sa[i];
register int *s1 = sa + len - sz, *b2 = b1 + sz;
if (cnt < sz) sais(s1, sa, sz, t + len, b, b1 + sz, cnt);
else for (i = 0; i < sz; i++) sa[s1[i]] = i;
for (i = 0; i < sz; i++) b2[i] = b1[sa[i]];
sort(s, sa, len, sz, sigma, t, b, cb, b2);
}

template<typename T>
inline void getHeight(T s, const int n) {
for (register int i = 1; i <= n; i++) rk[sa[i]] = i;
for (register int i = 0, j = 0, k = 0; i < n; ht[rk[i++]] = k)
for (k ? k-- : 0, j = sa[rk[i] - 1]; s[i + k] == s[j + k]; k++);

}

template<typename T>
inline void init(T s, const int n, const int sigma) {
sais(s, sa, n, t, rk, ht, sigma), rk[0] = 0;
getHeight(s, n - 1);
}

inline void solve() {
using namespace IO;
static char buf[MAXN];
register int t;
read(t);
while (t--) {
register int n = read(buf);
init(buf, n + 1, 256);
register int ans = 0;
for (register int i = 1; i <= n; i++)
ans += n - i + 1 - ht[i];
print(ans), print('\n');
}
}
}

int main() {
#ifdef DBG
freopen("in.in", "r", stdin);
#endif
SuffixArray::solve();
IO::flush();
return 0;
}

「SDOI2016」生成魔咒

链接

BZOJ4516

题解

题意就是每次加一个字符,求本质不同的子串的个数。

我们可以离线,先把所有数字离散化,然后把字符串倒过来建后缀数组,往最后加字符变成了添加一个后缀。

我们知道,在求出 $SA$ 之后,一个字符串的本质不同的子串的个数等于 $\frac {n(n + 1)} {2} - \sum height[i]$,每插入一个后缀,在所有已经插入的后缀中,找到它的前驱和后继。又因为两个后缀的 $LCP$,即重复计数的子串个数等于 $height$ 上的区间最小值。

时间复杂度 $O(n \log n)$

代码

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/*******************************************************************************
* Copyright (c) 2016-2017, xehoth
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name xehoth, nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY XEHOTH AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL XEHOTH AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include <bits/stdc++.h>
/**
* 「SDOI2016」生成魔咒 24-05-2017
* 后缀数组
* @author xehoth
*/
namespace IO {

inline char read() {
static const int IN_LEN = 1000000;
static char buf[IN_LEN], *s, *t;
s == t ? t = (s = buf) + fread(buf, 1, IN_LEN, stdin) : 0;
return s == t ? -1 : *s++;
}

template<typename T>
inline void read(T &x) {
static char c;
static bool iosig;
for (c = read(), iosig = false; !isdigit(c); c = read()) {
if (c == -1) return;
c == '-' ? iosig = true : 0;
}
for (x = 0; isdigit(c); c = read())
x = (x + (x << 2) << 1) + (c ^ '0');
iosig ? x = -x : 0;
}

inline int read(char *buf) {
register int s = 0;
register char c;
while (c = read(), isspace(c) && c != -1);
if (c == -1) {
*buf = '\0';
return -1;
}
do buf[s++] = c; while (c = read(), !isspace(c) && c != -1);
buf[s] = '\0';
return s;
}

const int OUT_LEN = 1000000;

char obuf[OUT_LEN], *oh = obuf;

inline void print(char c) {
oh == obuf + OUT_LEN ? (fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf) : 0;
*oh++ = c;
}

template<typename T>
inline void print(T x) {
static int buf[30], cnt;
if (x == 0) {
print('0');
} else {
x < 0 ? (print('-'), x = -x) : 0;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 | 48;
while (cnt) print((char)buf[cnt--]);
}
}

inline void flush() {
fwrite(obuf, 1, oh - obuf, stdout);
}
}

namespace SuffixArray {

const int MAXN = 100005;

int sa[MAXN], rk[MAXN << 1], ht[MAXN << 1];
bool t[MAXN << 1];

inline bool islms(const int i, const bool *t) {
return i > 0 && t[i] && !t[i - 1];
}

template<typename T>
inline void sort(T s, int *sa, const int len, const int sz, const int sigma,
bool *t, int *b, int *cb, int *p) {
memset(b, 0, sizeof(int) * sigma);
memset(sa, -1, sizeof(int) * len);
for (register int i = 0; i < len; i++) b[s[i]]++;
cb[0] = b[0];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i];
for (register int i = sz - 1; i >= 0; i--) sa[--cb[s[p[i]]]] = p[i];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i - 1];
for (register int i = 0; i < len; i++) if (sa[i] > 0 && !t[sa[i] - 1])
sa[cb[s[sa[i] - 1]]++] = sa[i] - 1;
cb[0] = b[0];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i];
for (register int i = len - 1; i >= 0; i--) if (sa[i] > 0 && t[sa[i] - 1])
sa[--cb[s[sa[i] - 1]]] = sa[i] - 1;
}

template<typename T>
inline void sais(T s, int *sa, const int len, bool *t, int *b, int *b1,
const int sigma) {
register int i, j, x, p = -1, cnt = 0, sz = 0, *cb = b + sigma;
for (t[len - 1] = 1, i = len - 2; i >= 0; i--) t[i] = s[i] < s[i + 1] ||
(s[i] == s[i + 1] && t[i + 1]);
for (i = 1; i < len; i++) if (t[i] && !t[i - 1]) b1[sz++] = i;
sort(s, sa, len, sz, sigma, t, b, cb, b1);
for (i = sz = 0; i < len; i++) if (islms(sa[i], t)) sa[sz++] = sa[i];
for (i = sz; i < len; i++) sa[i] = -1;
for (i = 0; i < sz; i++) {
for (x = sa[i], j = 0; j < len; j++) {
if (p == -1 || s[x + j] != s[p + j] || t[x + j] != t[p + j]) {
p = x, cnt++;
break;
} else if (j > 0 && (islms(x + j, t) || islms(p + j, t))) {
break;
}
}
sa[sz + (x >>= 1)] = cnt - 1;
}
for (i = j = len - 1; i >= sz; i--) if (sa[i] >= 0) sa[j--] = sa[i];
register int *s1 = sa + len - sz, *b2 = b1 + sz;
if (cnt < sz) sais(s1, sa, sz, t + len, b, b1 + sz, cnt);
else for (i = 0; i < sz; i++) sa[s1[i]] = i;
for (i = 0; i < sz; i++) b2[i] = b1[sa[i]];
sort(s, sa, len, sz, sigma, t, b, cb, b2);
}

template<typename T>
inline void getHeight(T s, const int n) {
for (register int i = 1; i <= n; i++) rk[sa[i]] = i;
for (register int i = 0, j = 0, k = 0; i < n; ht[rk[i++]] = k)
for (k ? k-- : 0, j = sa[rk[i] - 1]; s[i + k] == s[j + k]; k++);

}

template<typename T>
inline void init(T s, const int n, const int sigma) {
sais(s, sa, n, t, rk, ht, sigma), rk[0] = 0;
getHeight(s, n - 1);
}

#define long long long

long sum;
int fa[MAXN], min[MAXN];

inline int get(int x) {
while (x != fa[x]) x = fa[x] = fa[fa[x]];
return x;
}

inline void put(int x, int y) {
if ((x = get(x)) != (y = get(y))) {
fa[x] = y, sum += std::max(min[x], min[y]);
min[y] = std::min(min[y], min[x]);
}
}

inline void solve() {
using namespace IO;
register int n, m = 0;
read(n);
static int a[MAXN], tmp[MAXN];
for (register int i = n - 1; i >= 0; i--) read(a[i]), tmp[m++] = a[i];
std::sort(tmp, tmp + m), m = std::unique(tmp, tmp + m) - tmp;

for (register int i = 0; i < n; i++)
a[i] = std::lower_bound(tmp, tmp + m, a[i]) - tmp + 1;
m = n++;
init(a, n, n);
sum = (long)m * (m + 1) >> 1;
for (register int i = 1; i < n; i++) sum -= ht[i];
static long ans[MAXN];
ans[n] = sum;
for (register int i = 0; i <= n; ++i) fa[i] = i, min[i] = ht[i];
for (register int i = 0; i < m; i++)
sum -= m - i, put(rk[i], rk[i] + 1), ans[m - i] = sum;
for (register int i = 2; i <= n; i++) print(ans[i]), print('\n');
}

#undef long
}

int main() {
#ifdef DBG
freopen("in.in", "r", stdin);
#endif
SuffixArray::solve();
IO::flush();
return 0;
}

「AHOI2013」差异

链接

BZOJ3238

题解

因为每个后缀均被枚举了 $n - 1$ 次,所以

$$\sum_{1 \leq i < j \leq n}len(T_i) + len(T_j) = (n - 1) \times \frac {n(n + 1)} {2}$$

而两个后缀的 $lcp(T_i, T_j)$ 的长度应为 $min \text{ } height[k], k \in [rank[i] + 1, rank[j]]$,则:

$$\sum_{1 \leq i < j \leq n}len(lcp(T_i, T_j)) = \sum_{1 \leq i < j \leq n}min \text{ } height[k], k \in [i + 1, j]$$

即所有区间的 $height$ 的最小值之和,我们可以枚举区间的结尾 $i$,在这之前比 $height[i]$ 大的值都不不会对答案产生影响,考虑使用单调栈维护,当考虑到 $i$ 对答案的贡献时,记在 $i$ 之前第一个满足 $height[j] < height[i]$ 的 $j$,区间开头在 $[j + 1, i]$ 内的区间最小值均为 $height[i]$,即对答案的贡献为 $(i - j) \times height[i]$,从头枚举一遍即可。

时间复杂度 $O(n)$,目前 BZOJ rk1 black SA 不知道比 SAM 快到哪里去了

代码

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*******************************************************************************
* Copyright (c) 2016-2017, xehoth
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name xehoth, nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY XEHOTH AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL XEHOTH AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include <bits/stdc++.h>
/**
* 「AHOI2013」差异 24-05-2017
* 后缀数组
* @author xehoth
*/
namespace IO {

const int OUT_LEN = 100;

char obuf[OUT_LEN], *oh = obuf;

inline void print(char c) {
oh == obuf + OUT_LEN ? (fwrite(obuf, 1, oh - obuf, stdout), oh = obuf) : 0;
*oh++ = c;
}

template<typename T>
inline void print(T x) {
static int buf[30], cnt;
if (x == 0) {
print('0');
} else {
x < 0 ? (print('-'), x = -x) : 0;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 | 48;
while (cnt) print((char)buf[cnt--]);
}
}

inline void flush() {
fwrite(obuf, 1, oh - obuf, stdout);
}
}

namespace SuffixArray {

const int MAXN = 500005;

int sa[MAXN], rk[MAXN], ht[MAXN];
bool t[MAXN << 1];

inline bool islms(const int i, const bool *t) {
return i > 0 && t[i] && !t[i - 1];
}

template<typename T>
inline void sort(T s, int *sa, const int len, const int sz, const int sigma,
bool *t, int *b, int *cb, int *p) {
memset(b, 0, sizeof(int) * sigma);
memset(sa, -1, sizeof(int) * len);
for (register int i = 0; i < len; i++) b[s[i]]++;
cb[0] = b[0];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i];
for (register int i = sz - 1; i >= 0; i--) sa[--cb[s[p[i]]]] = p[i];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i - 1];
for (register int i = 0; i < len; i++) if (sa[i] > 0 && !t[sa[i] - 1])
sa[cb[s[sa[i] - 1]]++] = sa[i] - 1;
cb[0] = b[0];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i];
for (register int i = len - 1; i >= 0; i--) if (sa[i] > 0 && t[sa[i] - 1])
sa[--cb[s[sa[i] - 1]]] = sa[i] - 1;
}

template<typename T>
inline void sais(T s, int *sa, const int len, bool *t, int *b, int *b1,
const int sigma) {
register int i, j, x, p = -1, cnt = 0, sz = 0, *cb = b + sigma;
for (t[len - 1] = 1, i = len - 2; i >= 0; i--) t[i] = s[i] < s[i + 1] ||
(s[i] == s[i + 1] && t[i + 1]);
for (i = 1; i < len; i++) if (t[i] && !t[i - 1]) b1[sz++] = i;
sort(s, sa, len, sz, sigma, t, b, cb, b1);
for (i = sz = 0; i < len; i++) if (islms(sa[i], t)) sa[sz++] = sa[i];
for (i = sz; i < len; i++) sa[i] = -1;
for (i = 0; i < sz; i++) {
for (x = sa[i], j = 0; j < len; j++) {
if (p == -1 || s[x + j] != s[p + j] || t[x + j] != t[p + j]) {
p = x, cnt++;
break;
} else if (j > 0 && (islms(x + j, t) || islms(p + j, t))) {
break;
}
}
sa[sz + (x >>= 1)] = cnt - 1;
}
for (i = j = len - 1; i >= sz; i--) if (sa[i] >= 0) sa[j--] = sa[i];
register int *s1 = sa + len - sz, *b2 = b1 + sz;
if (cnt < sz) sais(s1, sa, sz, t + len, b, b1 + sz, cnt);
else for (i = 0; i < sz; i++) sa[s1[i]] = i;
for (i = 0; i < sz; i++) b2[i] = b1[sa[i]];
sort(s, sa, len, sz, sigma, t, b, cb, b2);
}

template<typename T>
inline void getHeight(T s, const int n) {
for (register int i = 1; i <= n; i++) rk[sa[i]] = i;
for (register int i = 0, j = 0, k = 0; i < n; ht[rk[i++]] = k)
for (k ? k-- : 0, j = sa[rk[i] - 1]; s[i + k] == s[j + k]; k++);
}

template<typename T>
inline void init(T s, const int n, const int sigma) {
sais(s, sa, n, t, rk, ht, sigma), rk[0] = ht[0] = 0;
getHeight(s, n - 1);
}

char s[MAXN];

#define long long long

inline void solve() {
using namespace IO;
register int n = fread(s, 1, MAXN, stdin);
s[n--] = '\0';
init(s, n + 1, 124);
static std::vector<int> st;
st.reserve(n);
static long f[MAXN];
register long ans = 0;
st.push_back(0);
register int *h = ht + 1;
for (register int i = 1; i < n; i++) {
while (!st.empty() && h[st.back()] > h[i]) st.pop_back();
ans += f[i] = f[st.back()] + (long)(i - st.back()) * h[i];
st.push_back(i);
}
print((long)(n - 1) * n * (n + 1) / 2 - 2 * ans);
}

#undef long
}

int main() {
#ifdef DBG
freopen("in.in", "r", stdin);
#endif
SuffixArray::solve();
IO::flush();
return 0;
}

「POJ2774」Long Long Message

链接

POJ2774

题解

题意:给定两个字符串求最长公共子串。

这是后缀数组的经典题,用后缀自动机也同样可做。

把两个串插分隔符连接起来建后缀数组,最长公共子串即转化为了最长公共前缀,我们枚举 $height$ 数组,如果相邻排名的两个后缀分别为 $S_1, S_2$ 的子串,我们就用这个 $height$ 更新答案,由于不相邻的后缀的最长公共前缀只会更小,所以我们这样扫一遍取最大即为答案。

时间复杂度 $O(n)$

代码

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/*******************************************************************************
* Copyright (c) 2016-2017, xehoth
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name xehoth, nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY XEHOTH AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL XEHOTH AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include <cstdio>
#include <iostream>
#include <climits>
#include <cctype>
#include <cstring>
/**
* 「POJ2774」Long Long Message 25-05-2017
* 后缀数组
* @author xehoth
*/
namespace IO {

inline char read() {
static const int IN_LEN = 1000000;
static char buf[IN_LEN], *s, *t;
s == t ? t = (s = buf) + fread(buf, 1, IN_LEN, stdin) : 0;
return s == t ? - 1 : *s++;
}

template<typename T>
inline void read(T &x) {
static char c;
static bool iosig;
for (c = read(), iosig = false; !isdigit(c); c = read()) {
if (c == -1) return;
c == '-' ? iosig = true : 0;
}
for (x = 0; isdigit(c); c = read())
x = (x + (x << 2) << 1) + (c ^ '0');
iosig ? x = -x : 0;
}

inline int read(char *buf) {
register int s = 0;
register char c;
while (c = read(), isspace(c) && c != -1);
if (c == -1) {
*buf = '\0';
return -1;
}
do buf[s++] = c; while (c = read(), !isspace(c) && c != -1);
buf[s] = '\0';
return s;
}

const int OUT_LEN = 1000000;

char obuf[OUT_LEN], *oh = obuf;

inline void print(char c) {
oh == obuf + OUT_LEN ? (fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf) : 0;
*oh++ = c;
}

template<typename T>
inline void print(T x) {
static int buf[30], cnt;
if (x == 0) {
print('0');
} else {
x < 0 ? (print('-'), x = -x) : 0;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 | 48;
while (cnt) print((char)buf[cnt--]);
}
}

inline void flush() {
fwrite(obuf, 1, oh - obuf, stdout);
}
}

namespace SuffixArray {

const int MAXN = 200005;

inline bool islms(const int i, const bool *t) {
return i > 0 && t[i] && !t[i - 1];
}

template<typename T>
inline void sort(T s, int *sa, const int len, const int sz, const int sigma,
bool *t, int *b, int *cb, int *p) {
memset(b, 0, sizeof(int) * sigma);
memset(sa, -1, sizeof(int) * len);
for (register int i = 0; i < len; i++) b[s[i]]++;
cb[0] = b[0];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i];
for (register int i = sz - 1; i >= 0; i--) sa[--cb[s[p[i]]]] = p[i];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i - 1];
for (register int i = 0; i < len; i++) if (sa[i] > 0 && !t[sa[i] - 1])
sa[cb[s[sa[i] - 1]]++] = sa[i] - 1;
cb[0] = b[0];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i];
for (register int i = len - 1; i >= 0; i--) if (sa[i] > 0 && t[sa[i] - 1])
sa[--cb[s[sa[i] - 1]]] = sa[i] - 1;
}

template<typename T>
inline void sais(T s, int *sa, const int len, bool *t, int *b, int *b1,
const int sigma) {
register int i, j, x, p = -1, sz = 0, cnt = 0, *cb = b + sigma;
for (t[len - 1] = 1, i = len - 2; i >= 0; i--) t[i] = s[i] < s[i + 1] ||
(s[i] == s[i + 1] && t[i + 1]);
for (i = 1; i < len; i++) if (t[i] && !t[i - 1]) b1[sz++] = i;
sort(s, sa, len, sz, sigma, t, b, cb, b1);
for (i = sz = 0; i < len; i++) if (islms(sa[i], t)) sa[sz++] = sa[i];
for (i = sz; i < len; i++) sa[i] = -1;
for (i = 0; i < sz; i++) {
for (x = sa[i], j = 0; j < len; j++) {
if (p == -1 || s[x + j] != s[p + j] || t[x + j] != t[p + j]) {
p = x, cnt++;
break;
} else if (j > 0 && (islms(x + j, t) || islms(p + j, t))) {
break;
}
}
sa[sz + (x >>= 1)] = cnt - 1;
}
for (i = j = len - 1; i >= sz; i--) if (sa[i] >= 0) sa[j--] = sa[i];
register int *s1 = sa + len - sz, *b2 = b1 + sz;
if (cnt < sz) sais(s1, sa, sz, t + len, b, b1 + sz, cnt);
else for (i = 0; i < sz; i++) sa[s1[i]] = i;
for (i = 0; i < sz; i++) b2[i] = b1[sa[i]];
sort(s, sa, len, sz, sigma, t, b, cb, b2);
}

template<typename T>
inline void getHeight(T s, const int n, int *sa, int *rk, int *ht) {
for (register int i = 1; i <= n; i++) rk[sa[i]] = i;
for (register int i = 0, j = 0, k = 0; i < n; ht[rk[i++]] = k)
for (k ? k-- : 0, j = sa[rk[i] - 1]; s[i + k] == s[j + k]; k++);
}

struct SuffixArray {
int sa[MAXN], rk[MAXN], ht[MAXN];
bool t[MAXN << 1];
int n;
char s[MAXN];

inline void build(const int sigma) {
s[n] = '\0', sais(s, sa, n + 1, t, rk, ht, sigma);
rk[0] = ht[0] = 0, getHeight(s, n, sa, rk, ht);
}
} suffixArray;

inline void solve() {
using namespace IO;
register int len1 = read(suffixArray.s);
suffixArray.s[len1] = 'z' + 1;
register int len2 = read(suffixArray.s + len1 + 1);
suffixArray.n = len1 + len2 + 1;
suffixArray.build('z' + 2);
register int ans = 0;
register int *sa = suffixArray.sa, *ht = suffixArray.ht;
for (register int i = 2; i <= len1 + len2; i++) {
if ((sa[i - 1] >= 0 && sa[i - 1] < len1 && sa[i] > len1) ||
(sa[i] >= 0 && sa[i] < len1 && sa[i - 1] > len1))
ans = std::max(ans, ht[i]);
}
print(ans);
}
}

int main() {
#ifdef DBG
freopen("in.in", "r", stdin);
#endif
SuffixArray::solve();
IO::flush();
return 0;
}

「POJ1743」Musical Theme

链接

POJ1743

题解

此题就是求不可重叠最长重复子串。

若可重叠则答案就是 $height$ 的最大值,但这里要求不可重叠。

考虑二分,把题目变成判定性问题:判断是否存在两个长度为 $k$ 的子串是相同的,且不重叠解决这个问题的关键还是利用 $height$,把排序后的后缀分成若干组,其中每组的后缀之间的 $height$ 值都不小于 $k$,有希望成为最长公共前缀不小于 $k$ 的两个后缀一定在同一组。然后对于每组后缀,只须判断每个后缀的 $sa$ 值的最大值和最小值之差是否不小于 $k$。如果有一组满足,则说明存在,否则不存在。

时间复杂度 $O(n \log n)$

代码

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/*******************************************************************************
* Copyright (c) 2016-2017, xehoth
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name xehoth, nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY XEHOTH AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL XEHOTH AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include <cctype>
#include <climits>
#include <cstdio>
#include <cstring>
#include <iostream>
/**
* 「POJ1743」Musical Theme 25-05-2017
* 后缀数组
* @author xehoth
*/
namespace IO {

inline char read() {
static const int IN_LEN = 1000000;
static char buf[IN_LEN], *s, *t;
s == t ? t = (s = buf) + fread(buf, 1, IN_LEN, stdin) : 0;
return s == t ? -1 : *s++;
}

template <typename T>
inline void read(T &x) {
static char c;
static bool iosig;
for (c = read(), iosig = false; !isdigit(c); c = read()) {
if (c == -1) return;
c == '-' ? iosig = true : 0;
}
for (x = 0; isdigit(c); c = read()) x = (x + (x << 2) << 1) + (c ^ '0');
iosig ? x = -x : 0;
}

inline int read(char *buf) {
register int s = 0;
register char c;
while (c = read(), isspace(c) && c != -1)
;
if (c == -1) {
*buf = '\0';
return -1;
}
do
buf[s++] = c;
while (c = read(), !isspace(c) && c != -1);
buf[s] = '\0';
return s;
}

const int OUT_LEN = 1000000;

char obuf[OUT_LEN], *oh = obuf;

inline void print(char c) {
oh == obuf + OUT_LEN ? (fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf) : 0;
*oh++ = c;
}

template <typename T>
inline void print(T x) {
static int buf[30], cnt;
if (x == 0) {
print('0');
} else {
x < 0 ? (print('-'), x = -x) : 0;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 | 48;
while (cnt) print((char)buf[cnt--]);
}
}

inline void flush() { fwrite(obuf, 1, oh - obuf, stdout); }
}

namespace SuffixArray {

const int MAXN = 200005;

inline bool islms(const int i, const bool *t) {
return i > 0 && t[i] && !t[i - 1];
}

template <typename T>
inline void sort(T s, int *sa, const int len, const int sz, const int sigma,
bool *t, int *b, int *cb, int *p) {
memset(b, 0, sizeof(int) * sigma);
memset(sa, -1, sizeof(int) * len);
for (register int i = 0; i < len; i++) b[s[i]]++;
cb[0] = b[0];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i];
for (register int i = sz - 1; i >= 0; i--) sa[--cb[s[p[i]]]] = p[i];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i - 1];
for (register int i = 0; i < len; i++)
if (sa[i] > 0 && !t[sa[i] - 1]) sa[cb[s[sa[i] - 1]]++] = sa[i] - 1;
cb[0] = b[0];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i];
for (register int i = len - 1; i >= 0; i--)
if (sa[i] > 0 && t[sa[i] - 1]) sa[--cb[s[sa[i] - 1]]] = sa[i] - 1;
}

template <typename T>
inline void sais(T s, int *sa, const int len, bool *t, int *b, int *b1,
const int sigma) {
register int i, j, x, p = -1, sz = 0, cnt = 0, *cb = b + sigma;
for (t[len - 1] = 1, i = len - 2; i >= 0; i--)
t[i] = s[i] < s[i + 1] || (s[i] == s[i + 1] && t[i + 1]);
for (i = 1; i < len; i++)
if (t[i] && !t[i - 1]) b1[sz++] = i;
sort(s, sa, len, sz, sigma, t, b, cb, b1);
for (i = sz = 0; i < len; i++)
if (islms(sa[i], t)) sa[sz++] = sa[i];
for (i = sz; i < len; i++) sa[i] = -1;
for (i = 0; i < sz; i++) {
for (x = sa[i], j = 0; j < len; j++) {
if (p == -1 || s[x + j] != s[p + j] || t[x + j] != t[p + j]) {
p = x, cnt++;
break;
} else if (j > 0 && (islms(x + j, t) || islms(p + j, t))) {
break;
}
}
sa[sz + (x >>= 1)] = cnt - 1;
}
for (i = j = len - 1; i >= sz; i--)
if (sa[i] >= 0) sa[j--] = sa[i];
register int *s1 = sa + len - sz, *b2 = b1 + sz;
if (cnt < sz)
sais(s1, sa, sz, t + len, b, b1 + sz, cnt);
else
for (i = 0; i < sz; i++) sa[s1[i]] = i;
for (i = 0; i < sz; i++) b2[i] = b1[sa[i]];
sort(s, sa, len, sz, sigma, t, b, cb, b2);
}

template <typename T>
inline void getHeight(T s, const int n, int *sa, int *rk, int *ht) {
for (register int i = 1; i <= n; i++) rk[sa[i]] = i;
for (register int i = 0, j = 0, k = 0; i < n; ht[rk[i++]] = k)
for (k ? k-- : 0, j = sa[rk[i] - 1]; s[i + k] == s[j + k]; k++)
;
}

struct SuffixArray {
int sa[MAXN], rk[MAXN], ht[MAXN];
bool t[MAXN << 1];
int n;
int s[MAXN];

inline void build(const int sigma) {
s[n] = '\0', sais(s, sa, n + 1, t, rk, ht, sigma);
rk[0] = ht[0] = 0, getHeight(s, n, sa, rk, ht);
}
} suffixArray;

int *sa, *ht;

inline bool check(int k, int n) {
register int max, min;
max = min = sa[1];
for (register int i = 2; i <= n; i++) {
if (ht[i] >= k && i < n) {
min = std::min(min, sa[i]), max = std::max(max, sa[i]);
continue;
}
if (max - min >= k) return true;
max = min = sa[i];
}
return false;
}

inline void solve() {
using namespace IO;
register int n;
while (read(n), n) {
for (register int i = 0; i < n; i++) read(suffixArray.s[i]);
for (int i = 0; i < n - 1; i++)
suffixArray.s[i] = suffixArray.s[i + 1] - suffixArray.s[i] + 100;
suffixArray.n = n - 1, suffixArray.build(256);
sa = suffixArray.sa, ht = suffixArray.ht;
register int l = 0, r = n + 1, ans = 0;
while (r - l > 1) {
register int mid = l + r >> 1;
check(mid, n) ? l = mid : r = mid;
}
print(++l < 5 ? 0 : l), print('\n');
}
}
}

int main() {
#ifdef DBG
freopen("in.in", "r", stdin);
freopen("out.out", "w", stdout);
freopen("debug.log", "w", stderr);
#endif
SuffixArray::solve();
IO::flush();
return 0;
}

「POJ3261」Milk Patterns

链接

POJ3261

题解

题意: 可重叠的 $k$ 次最长重复子串。

思路同上,分组然后二分判定就好了。

代码

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/*******************************************************************************
* Copyright (c) 2016-2017, xehoth
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name xehoth, nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY XEHOTH AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL XEHOTH AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include <cctype>
#include <climits>
#include <cstdio>
#include <cstring>
#include <iostream>
/**
* 「POJ3261」Milk Patterns 25-05-2017
* 后缀数组
* @author xehoth
*/
namespace IO {

inline char read() {
static const int IN_LEN = 1000000;
static char buf[IN_LEN], *s, *t;
s == t ? t = (s = buf) + fread(buf, 1, IN_LEN, stdin) : 0;
return s == t ? -1 : *s++;
}

template <typename T>
inline void read(T &x) {
static char c;
static bool iosig;
for (c = read(), iosig = false; !isdigit(c); c = read()) {
if (c == -1) return;
c == '-' ? iosig = true : 0;
}
for (x = 0; isdigit(c); c = read()) x = (x + (x << 2) << 1) + (c ^ '0');
iosig ? x = -x : 0;
}

inline int read(char *buf) {
register int s = 0;
register char c;
while (c = read(), isspace(c) && c != -1)
;
if (c == -1) {
*buf = '\0';
return -1;
}
do
buf[s++] = c;
while (c = read(), !isspace(c) && c != -1);
buf[s] = '\0';
return s;
}

const int OUT_LEN = 1000000;

char obuf[OUT_LEN], *oh = obuf;

inline void print(char c) {
oh == obuf + OUT_LEN ? (fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf) : 0;
*oh++ = c;
}

template <typename T>
inline void print(T x) {
static int buf[30], cnt;
if (x == 0) {
print('0');
} else {
x < 0 ? (print('-'), x = -x) : 0;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 | 48;
while (cnt) print((char)buf[cnt--]);
}
}

inline void flush() { fwrite(obuf, 1, oh - obuf, stdout); }
}

namespace SuffixArray {

inline bool islms(const int i, const bool *t) {
return i > 0 && t[i] && !t[i - 1];
}

template <typename T>
inline void sort(T s, int *sa, const int len, const int sz, const int sigma,
bool *t, int *b, int *cb, int *p) {
memset(b, 0, sizeof(int) * sigma);
memset(sa, -1, sizeof(int) * len);
for (register int i = 0; i < len; i++) b[s[i]]++;
cb[0] = b[0];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i];
for (register int i = sz - 1; i >= 0; i--) sa[--cb[s[p[i]]]] = p[i];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i - 1];
for (register int i = 0; i < len; i++)
if (sa[i] > 0 && !t[sa[i] - 1]) sa[cb[s[sa[i] - 1]]++] = sa[i] - 1;
cb[0] = b[0];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i];
for (register int i = len - 1; i >= 0; i--)
if (sa[i] > 0 && t[sa[i] - 1]) sa[--cb[s[sa[i] - 1]]] = sa[i] - 1;
}

template <typename T>
inline void sais(T s, int *sa, const int len, bool *t, int *b, int *b1,
const int sigma) {
register int i, j, x, p = -1, cnt = 0, sz = 0, *cb = b + sigma;
for (t[len - 1] = 1, i = len - 2; i >= 0; i--)
t[i] = s[i] < s[i + 1] || (s[i] == s[i + 1] && t[i + 1]);
for (i = 1; i < len; i++)
if (t[i] && !t[i - 1]) b1[sz++] = i;
sort(s, sa, len, sz, sigma, t, b, cb, b1);
for (i = sz = 0; i < len; i++)
if (islms(sa[i], t)) sa[sz++] = sa[i];
for (i = sz; i < len; i++) sa[i] = -1;
for (i = 0; i < sz; i++) {
for (x = sa[i], j = 0; j < len; j++) {
if (p == -1 || s[x + j] != s[p + j] || t[x + j] != t[p + j]) {
p = x, cnt++;
break;
} else if (j > 0 && (islms(x + j, t) || islms(p + j, t))) {
break;
}
}
sa[sz + (x >>= 1)] = cnt - 1;
}
for (i = j = len - 1; i >= sz; i--)
if (sa[i] >= 0) sa[j--] = sa[i];
register int *s1 = sa + len - sz, *b2 = b1 + sz;
if (cnt < sz)
sais(s1, sa, sz, t + len, b, b1 + sz, cnt);
else
for (i = 0; i < sz; i++) sa[s1[i]] = i;
for (i = 0; i < sz; i++) b2[i] = b1[sa[i]];
sort(s, sa, len, sz, sigma, t, b, cb, b2);
}

template <typename T>
inline void getHeight(T s, const int n, int *sa, int *rk, int *ht) {
for (register int i = 1; i <= n; i++) rk[sa[i]] = i;
for (register int i = 0, j = 0, k = 0; i < n; ht[rk[i++]] = k)
for (k ? k-- : 0, j = sa[rk[i] - 1]; s[i + k] == s[j + k]; k++)
;
}

const int MAXN = 20500;

struct SuffixArray {
int sa[MAXN], rk[MAXN], ht[MAXN];
int s[MAXN];
bool t[MAXN << 1];
int n;

inline void build(const int sigma) {
s[n] = 0, sais(s, sa, n + 1, t, rk, ht, sigma);
ht[0] = rk[0] = 0, getHeight(s, n, sa, rk, ht);
}

inline int &operator[](const int i) { return s[i]; }
} suffixArray;

int *ht;

inline bool check(int x, int k, int n) {
register int cnt = 1;
for (register int i = 2; i <= n; i++) {
if (ht[i] >= x && i < n) {
cnt++;
continue;
}
if (cnt >= k) return true;
cnt = 1;
}
return false;
}

inline void solve() {
using namespace IO;
register int n, k, max = INT_MIN;
read(n), read(k);
for (register int i = 0; i < n; i++)
read(suffixArray[i]), max = std::max(max, suffixArray[i] += 5);
suffixArray.n = n++, suffixArray.build(max + 5), ht = suffixArray.ht;
register int l = 1, r = n + 2;
while (r - l > 1) {
register int mid = l + r >> 1;
check(mid, k, n) ? l = mid : r = mid;
}
print(l), print('\n');
}
}

int main() {
#ifdef DBG
freopen("in.in", "r", stdin);
freopen("out.out", "w", stdout);
freopen("debug.log", "w", stderr);
#endif
SuffixArray::solve();
IO::flush();
return 0;
}

「BZOJ2882」工艺

链接

BZOJ2882

题解

此题就是求字符串的最小循环表示,也可以用最小表示法,后缀自动机做。

由于此题的数据有 $0$,我们对于每个树先全部加上 $1$,把原串 $S$ 复制一遍变为 $SS$,我们再往后面加一个最大字符,然后构建后缀数组,找到 $sa[1]$ 所对应原串中的位置输出就可以了,即输出 $SS_{sa[1] \% n} \text{ ~ } SS_{sa[1] \% n + n - 1}$。

代码

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/*******************************************************************************
* Copyright (c) 2016-2017, xehoth
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name xehoth, nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY XEHOTH AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL XEHOTH AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include <bits/stdc++.h>
/**
* 「BZOJ2882」工艺 31-05-2017
* 后缀数组
* @author xehoth
*/
namespace IO {

inline char read() {
static const int IN_LEN = 1000000;
static char buf[IN_LEN], *s, *t;
s == t ? t = (s = buf) + fread(buf, 1, IN_LEN, stdin) : 0;
return s == t ? -1 : *s++;
}

template <typename T>
inline void read(T &x) {
static char c;
static bool iosig;
for (c = read(), iosig = false; !isdigit(c); c = read()) {
if (c == -1) return;
c == '-' ? iosig = true : 0;
}
for (x = 0; isdigit(c); c = read()) x = (x + (x << 2) << 1) + (c ^ '0');
iosig ? x = -x : 0;
}

inline int read(char *buf) {
register int s = 0;
register char c;
while (c = read(), isspace(c) && c != -1)
;
if (c == -1) {
*buf = '\0';
return -1;
}
do
buf[s++] = c;
while (c = read(), !isspace(c) && c != -1);
buf[s] = '\0';
return s;
}

const int OUT_LEN = 1000000;

char obuf[OUT_LEN], *oh = obuf;
inline void print(char c) {
oh == obuf + OUT_LEN ? (fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf) : 0;
*oh++ = c;
}

template <typename T>
inline void print(T x) {
static int buf[30], cnt;
if (x == 0) {
print('0');
} else {
x < 0 ? (print('-'), x = -x) : 0;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 | 48;
while (cnt) print((char)buf[cnt--]);
}
}

inline void flush() { fwrite(obuf, 1, oh - obuf, stdout); }
}

namespace SuffixArray {

const int MAXN = 300000 * 2 + 1000;

inline bool islms(const int i, const bool *t) {
return i > 0 && t[i] && !t[i - 1];
}

template <typename T>
inline void sort(T s, int *sa, const int len, const int sz, const int sigma,
bool *t, int *b, int *cb, int *p) {
memset(b, 0, sizeof(int) * sigma);
memset(sa, -1, sizeof(int) * len);
for (register int i = 0; i < len; i++) b[s[i]]++;
cb[0] = b[0];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i];
for (register int i = sz - 1; i >= 0; i--) sa[--cb[s[p[i]]]] = p[i];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i - 1];
for (register int i = 0; i < len; i++)
if (sa[i] > 0 && !t[sa[i] - 1]) sa[cb[s[sa[i] - 1]]++] = sa[i] - 1;
cb[0] = b[0];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i];
for (register int i = len - 1; i >= 0; i--)
if (sa[i] > 0 && t[sa[i] - 1]) sa[--cb[s[sa[i] - 1]]] = sa[i] - 1;
}

template <typename T>
inline void sais(T s, int *sa, const int len, bool *t, int *b, int *b1,
const int sigma) {
register int i, j, x, p = -1, sz = 0, cnt = 0, *cb = b + sigma;
for (t[len - 1] = 1, i = len - 2; i >= 0; i--)
t[i] = s[i] < s[i + 1] || (s[i] == s[i + 1] && t[i + 1]);
for (i = 1; i < len; i++)
if (t[i] && !t[i - 1]) b1[sz++] = i;
sort(s, sa, len, sz, sigma, t, b, cb, b1);
for (i = sz = 0; i < len; i++)
if (islms(sa[i], t)) sa[sz++] = sa[i];
for (i = sz; i < len; i++) sa[i] = -1;
for (i = 0; i < sz; i++) {
for (x = sa[i], j = 0; j < len; j++) {
if (p == -1 || s[x + j] != s[p + j] || t[x + j] != t[p + j]) {
p = x, cnt++;
break;
} else if (j > 0 && (islms(x + j, t) || islms(p + j, t))) {
break;
}
}
sa[sz + (x >>= 1)] = cnt - 1;
}
for (i = j = len - 1; i >= sz; i--)
if (sa[i] >= 0) sa[j--] = sa[i];
register int *s1 = sa + len - sz, *b2 = b1 + sz;
if (cnt < sz)
sais(s1, sa, sz, t + len, b, b1 + sz, cnt);
else
for (i = 0; i < sz; i++) sa[s1[i]] = i;
for (i = 0; i < sz; i++) b2[i] = b1[sa[i]];
sort(s, sa, len, sz, sigma, t, b, cb, b2);
}

template <typename T>
inline void getHeight(T s, const int n, int *sa, int *rk, int *ht) {
for (register int i = 1; i <= n; i++) rk[sa[i]] = i;
for (register int i = 0, j = 0, k = 0; i < n; ht[rk[i++]] = k)
for (k ? k-- : 0, j = sa[rk[i] - 1]; s[i + k] == s[j + k]; k++)
;
}

struct SuffixArray {
int sa[MAXN], rk[MAXN], ht[MAXN], n;
bool t[MAXN << 1];
int s[MAXN];

inline void build(const int sigma) {
s[n] = 0, sais(s, sa, n + 1, t, ht, rk, sigma);
/* rk[0] = ht[0] = 0, getHeight(s, n, sa, rk, ht); */
}
} suffixArray;

inline void solve() {
using namespace IO;
register int n, max = 0;
read(n);
for (register int i = 0; i < n; i++)
read(suffixArray.s[i]), suffixArray.s[i]++;
max = *std::max_element(suffixArray.s, suffixArray.s + n);
memcpy(suffixArray.s + n, suffixArray.s, sizeof(int) * n);
suffixArray.s[(suffixArray.n = n << 1 | 1) - 1] = max + 1;
suffixArray.build(max + 2);
register int t = suffixArray.sa[1] % n;
for (register int i = 0; i < n - 1; i++)
print(suffixArray.s[i + t] - 1), print(' ');
print(suffixArray.s[n + t - 1] - 1);
}
}

int main() {
SuffixArray::solve();
IO::flush();
return 0;
}

「POJ 2406」Power Strings

链接

POJ2406

题解

*题意: * 如果一个字符串 $L$ 是由某个字符串 $S$ 重复 $R$ 次而得到的, 则称 $L$ 是一个连续重复串。$R$ 是这个字符串的重复次数,给你一个连续重复串 $L$,求 $R$ 的最大值。

此题就是后缀数组求连续重复子串的经典题,也可以用 KMP 做。

我们先构建 $S$ 的后缀数组,枚举长度 $k$,然后判断是否满足以下条件 ($S$ 的循环节):

  1. $len(s) % k = 0$
  2. $lcp(Suffix(0), Suffix(k)) = n - k$

我们可以这样理解,再拿一个串 $S’$ 在原串 $S$ 下匹配,枚举长度 $k$ 即为从 $S’_k$ 开始匹配,判断 $S$ 与 $S’$ 匹配长度是否恰为总长 - 跳过的长度,即 $n - k$。

代码

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/*******************************************************************************
* Copyright (c) 2016-2017, xehoth
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name xehoth, nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY XEHOTH AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL XEHOTH AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include <algorithm>
#include <cctype>
#include <climits>
#include <cstdio>
#include <cstring>
#include <iostream>
/**
* 「POJ 2406」Power Strings 31-05-2017
* 后缀数组
* @author xehoth
*/
namespace IO {

inline char read() {
static const int IN_LEN = 1000000;
static char buf[IN_LEN], *s, *t;
s == t ? t = (s = buf) + fread(buf, 1, IN_LEN, stdin) : 0;
return s == t ? -1 : *s++;
}

template <typename T>
inline void read(T &x) {
static char c;
static bool iosig;
for (c = read(), iosig = false; !isdigit(c); c = read()) {
if (c == -1) return;
c == '-' ? iosig = true : 0;
}
for (x = 0; isdigit(c); c = read()) x = (x + (x << 2) << 1) + (c ^ '0');
iosig ? x = -x : 0;
}

inline int read(char *buf) {
register int s = 0;
register char c;
while (c = read(), isspace(c) && c != -1)
;
if (c == -1) {
*buf = '\0';
return -1;
}
do
buf[s++] = c;
while (c = read(), !isspace(c) && c != -1);
buf[s] = '\0';
return s;
}

const int OUT_LEN = 1000000;

char obuf[OUT_LEN], *oh = obuf;
inline void print(char c) {
oh == obuf + OUT_LEN ? (fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf) : 0;
*oh++ = c;
}

template <typename T>
inline void print(T x) {
static int buf[30], cnt;
if (x == 0) {
print('0');
} else {
x < 0 ? (print('-'), x = -x) : 0;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 | 48;
while (cnt) print((char)buf[cnt--]);
}
}

inline void flush() { fwrite(obuf, 1, oh - obuf, stdout); }
}

namespace SuffixArray {

const int MAXN = 1000005;

inline bool islms(const int i, const bool *t) {
return i > 0 && t[i] && !t[i - 1];
}

template <typename T>
inline void sort(T s, int *sa, const int len, const int sz, const int sigma,
bool *t, int *b, int *cb, int *p) {
memset(b, 0, sizeof(int) * sigma);
memset(sa, -1, sizeof(int) * len);
for (register int i = 0; i < len; i++) b[s[i]]++;
cb[0] = b[0];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i];
for (register int i = sz - 1; i >= 0; i--) sa[--cb[s[p[i]]]] = p[i];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i - 1];
for (register int i = 0; i < len; i++)
if (sa[i] > 0 && !t[sa[i] - 1]) sa[cb[s[sa[i] - 1]]++] = sa[i] - 1;
cb[0] = b[0];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i];
for (register int i = len - 1; i >= 0; i--)
if (sa[i] > 0 && t[sa[i] - 1]) sa[--cb[s[sa[i] - 1]]] = sa[i] - 1;
}

template <typename T>
inline void sais(T s, int *sa, const int len, bool *t, int *b, int *b1,
const int sigma) {
register int i, j, x, p = -1, sz = 0, cnt = 0, *cb = b + sigma;
for (t[len - 1] = 1, i = len - 2; i >= 0; i--)
t[i] = s[i] < s[i + 1] || (s[i] == s[i + 1] && t[i + 1]);
for (i = 1; i < len; i++)
if (t[i] && !t[i - 1]) b1[sz++] = i;
sort(s, sa, len, sz, sigma, t, b, cb, b1);
for (i = sz = 0; i < len; i++)
if (islms(sa[i], t)) sa[sz++] = sa[i];
for (i = sz; i < len; i++) sa[i] = -1;
for (i = 0; i < sz; i++) {
for (x = sa[i], j = 0; j < len; j++) {
if (p == -1 || s[x + j] != s[p + j] || t[x + j] != t[p + j]) {
p = x, cnt++;
break;
} else if (j > 0 && (islms(x + j, t) || islms(p + j, t))) {
break;
}
}
sa[sz + (x >>= 1)] = cnt - 1;
}
for (i = j = len - 1; i >= sz; i--)
if (sa[i] >= 0) sa[j--] = sa[i];
register int *s1 = sa + len - sz, *b2 = b1 + sz;
if (cnt < sz)
sais(s1, sa, sz, t + len, b, b1 + sz, cnt);
else
for (i = 0; i < sz; i++) sa[s1[i]] = i;
for (i = 0; i < sz; i++) b2[i] = b1[sa[i]];
sort(s, sa, len, sz, sigma, t, b, cb, b2);
}

template <typename T>
inline void getHeight(T s, const int n, int *sa, int *rk, int *ht) {
for (register int i = 1; i <= n; i++) rk[sa[i]] = i;
for (register int i = 0, j = 0, k = 0; i < n; ht[rk[i++]] = k)
for (k ? k-- : 0, j = sa[rk[i] - 1]; s[j + k] == s[i + k]; k++)
;
}

struct SuffixArray {
int sa[MAXN], rk[MAXN], ht[MAXN];
char s[MAXN];
int n;
bool t[MAXN << 1];

inline void build(const int sigma) {
s[n] = 0, sais(s, sa, n + 1, t, rk, ht, sigma);
rk[0] = ht[0], getHeight(s, n, sa, rk, ht);
}
} suffixArray;

inline void solve() {
using namespace IO;
for (register int n; n = read(suffixArray.s), strcmp(suffixArray.s, ".");) {
suffixArray.n = n;
suffixArray.build(124);
static int min[MAXN];
register int *rk = suffixArray.rk, *ht = suffixArray.ht;
min[rk[0]] = INT_MAX;
for (register int i = rk[0] - 1; i; i--)
min[i] = std::min(ht[i + 1], min[i + 1]);
for (register int i = rk[0] + 1; i <= n; i++)
min[i] = std::min(ht[i], min[i - 1]);
for (register int i = 1; i <= n; i++) {
if (n % i == 0 && min[rk[i]] == n - i) {
print(n / i), print('\n');
break;
}
}
}
}
}

int main() {
#ifdef DBG
freopen("in.in", "r", stdin);
#endif
SuffixArray::solve();
IO::flush();
return 0;
}

字符串匹配

字符串匹配有很多做法,这里记录一下后缀数组的做法,这里只实现了单串匹配 $O(m \log n)$ 的做法,$O(m + \log n)$ 的做法详见论文。

实现

我们可以利用后缀数组字典序的单调性,通过二分在 $O(m \log n)$ 的时间内完成,其中 strncmp(s1, s2, size) 函数的作用是比较 $s_1, s_2$ 前 $size$ 个字符,如果不同,则返回第一个不同位置 $k$ 的 $s_1[k] - s_2[k]$。

代码

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/*******************************************************************************
* Copyright (c) 2016-2017, xehoth
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name xehoth, nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY XEHOTH AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL XEHOTH AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include <bits/stdc++.h>
/**
* 「字符串匹配」01-06-2017
* 后缀数组
* @author xehoth
*/
namespace IO {

inline char read() {
static const int IN_LEN = 1000000;
static char buf[IN_LEN], *s, *t;
s == t ? t = (s = buf) + fread(buf, 1, IN_LEN, stdin) : 0;
return s == t ? -1 : *s++;
}

template <typename T>
inline void read(T &x) {
static char c;
static bool iosig;
for (c = read(), iosig = false; !isdigit(c); c = read()) {
if (c == -1) return;
c == '-' ? iosig = true : 0;
}
for (x = 0; isdigit(c); c = read()) x = (x + (x << 2) << 1) + (c ^ '0');
iosig ? x = -x : 0;
}

inline int read(char *buf) {
register int s = 0;
register char c;
while (c = read(), isspace(c) && c != -1)
;
if (c == -1) {
*buf = 0;
return -1;
}
do
buf[s++] = c;
while (c = read(), !isspace(c) && c != -1);
buf[s] = 0;
return s;
}

const int OUT_LEN = 1000000;

char obuf[OUT_LEN], *oh = obuf;

inline void print(char c) {
oh == obuf + OUT_LEN ? (fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf) : 0;
*oh++ = c;
}

template <typename T>
inline void print(T x) {
static int buf[30], cnt;
if (x == 0) {
print('0');
} else {
x < 0 ? (print('-'), x = -x) : 0;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 | 48;
while (cnt) print((char)buf[cnt--]);
}
}

inline void flush() { fwrite(obuf, 1, oh - obuf, stdout); }
}

namespace SuffixArray {

const int MAXN = 1000010;

inline bool islms(const int i, const bool *t) {
return i > 0 && t[i] && !t[i - 1];
}

template <typename T>
inline void sort(T s, int *sa, const int len, const int sz, const int sigma,
bool *t, int *b, int *cb, int *p) {
memset(b, 0, sizeof(int) * sigma);
memset(sa, -1, sizeof(int) * len);
for (register int i = 0; i < len; i++) b[s[i]]++;
cb[0] = b[0];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i];
for (register int i = sz - 1; i >= 0; i--) sa[--cb[s[p[i]]]] = p[i];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i - 1];
for (register int i = 0; i < len; i++)
if (sa[i] > 0 && !t[sa[i] - 1]) sa[cb[s[sa[i] - 1]]++] = sa[i] - 1;
cb[0] = b[0];
for (register int i = 1; i < sigma; i++) cb[i] = cb[i - 1] + b[i];
for (register int i = len - 1; i >= 0; i--)
if (sa[i] > 0 && t[sa[i] - 1]) sa[--cb[s[sa[i] - 1]]] = sa[i] - 1;
}

template <typename T>
inline void sais(T s, int *sa, const int len, bool *t, int *b, int *b1,
const int sigma) {
register int i, j, x, p = -1, cnt = 0, sz = 0, *cb = b + sigma;
for (t[len - 1] = 1, i = len - 2; i >= 0; i--)
t[i] = s[i] < s[i + 1] || (s[i] == s[i + 1] && t[i + 1]);
for (i = 1; i < len; i++)
if (t[i] && !t[i - 1]) b1[sz++] = i;
sort(s, sa, len, sz, sigma, t, b, cb, b1);
for (i = sz = 0; i < len; i++)
if (islms(sa[i], t)) sa[sz++] = sa[i];
for (i = sz; i < len; i++) sa[i] = -1;
for (i = 0; i < sz; i++) {
for (x = sa[i], j = 0; j < len; j++) {
if (p == -1 || s[x + j] != s[p + j] || t[x + j] != t[p + j]) {
p = x, cnt++;
break;
} else if (j > 0 && (islms(x + j, t) || islms(p + j, t))) {
break;
}
}
sa[sz + (x >>= 1)] = cnt - 1;
}
for (i = j = len - 1; i >= sz; i--)
if (sa[i] >= 0) sa[j--] = sa[i];
register int *s1 = sa + len - sz, *b2 = b1 + sz;
if (cnt < sz)
sais(s1, sa, sz, t + len, b, b1 + sz, cnt);
else
for (i = 0; i < sz; i++) sa[s1[i]] = i;
for (i = 0; i < sz; i++) b2[i] = b1[sa[i]];
sort(s, sa, len, sz, sigma, t, b, cb, b2);
}

template <typename T>
inline void getHeight(T s, const int n, int *sa, int *rk, int *ht) {
for (register int i = 1; i <= n; i++) rk[sa[i]] = i;
for (register int i = 0, j = 0, k = 0; i < n; ht[rk[i++]] = k)
for (k ? k-- : 0, j = sa[rk[i] - 1]; s[i + k] == s[j + k]; k++)
;
}

struct SuffixArray {
int sa[MAXN], rk[MAXN], ht[MAXN];
bool t[MAXN << 1];
int n;
char s[MAXN];

inline void build(const int sigma) {
s[n] = 0, sais(s, sa, n + 1, t, rk, ht, sigma);
/* rk[0] = ht[0] = 0, getHeight(s, n, sa, rk, min[0]); */
}
} suffixArray;

int *sa;

inline int cmpSuffix(const char *p, const int len, const int pos) {
return strncmp(p, suffixArray.s + sa[pos], len);
}

inline void match(const char *p, const int len, int l, int r,
std::vector<int> &vc) {
if (cmpSuffix(p, len, l + 1) < 0 || cmpSuffix(p, len, r - 1) > 0) return;
while (r - l > 1) {
register int mid = l + r >> 1;
register int res = cmpSuffix(p, len, mid);
if (res == 0) {
vc.push_back(sa[mid]);
match(p, len, l, mid, vc), match(p, len, mid, r, vc);
return;
}
res < 0 ? r = mid : l = mid;
}
}

inline void solve() {
using namespace IO;
suffixArray.n = read(suffixArray.s);
suffixArray.build(124), sa = suffixArray.sa;
static char p[MAXN];
static std::vector<int> vc;
vc.reserve(suffixArray.n);
match(p, read(p), 0, suffixArray.n, vc);
std::sort(vc.begin(), vc.end());
for (register int i = 0; i < vc.size(); i++) print(vc[i] + 1), print('\n');
if (vc.empty()) print('N'), print('O');
}
}

int main() {
#ifdef DBG
freopen("in.in", "r", stdin);
#endif
SuffixArray::solve();
IO::flush();
return 0;
}

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×