因为自己准备的后缀数组模板对oldrk和rk的 [len+1,n∗2] 部分进行初始化导致能过掉单组样例但是多组样例过不去。
如果在黑暗爆炸下载数据重复填装 8.in
和 10.in
的话,会看到非常诡异的数字出现。
参考代码:
错误的:
namespace SA {
int len;
int sa[MAXN], rk[MAXN << 1], oldrk[MAXN << 1], id[MAXN], cnt[MAXN];
void run(char s[], int _len) { // call: run(str, strlen(str+1));
len = _len;
int m = max(len, 300);
// memset(cnt, 0, sizeof(cnt));
for (int i = 0; i <= m; i++) cnt[i] = 0;
for (int i = 1; i <= len; i++) ++cnt[rk[i] = s[i]];
for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
for (int i = len; i >= 1; i--) sa[cnt[rk[i]]--] = i;
for (int w = 1; w <= len; w <<= 1) {
// memset(cnt, 0, sizeof(cnt));
for (int i = 0; i <= m; i++) cnt[i] = 0;
for (int i = 1; i <= len; i++) id[i] = sa[i];
for (int i = 1; i <= len; i++) ++cnt[rk[id[i] + w]];
for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
for (int i = len; i >= 1; i--) sa[cnt[rk[id[i] + w]]--] = id[i];
for (int i = 0; i <= m; i++) cnt[i] = 0;
// memset(cnt, 0, sizeof(cnt));
for (int i = 1; i <= len; i++) id[i] = sa[i];
for (int i = 1; i <= len; i++) ++cnt[rk[id[i]]];
for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
for (int i = len; i >= 1; i--) sa[cnt[rk[id[i]]]--] = id[i];
// memcpy(oldrk, rk, sizeof(rk));
for (int i = 0; i <= len; i++) oldrk[i] = rk[i];
for (int p = 0, i = 1; i <= len; i++) {
if (oldrk[sa[i]] == oldrk[sa[i - 1]] && oldrk[sa[i] + w] == oldrk[sa[i - 1] + w]) rk[sa[i]] = p;
else rk[sa[i]] = ++p;
}
}
}
void get_height(char s[]) { // step2 call: get_height(str)
int k = 0;
for (int i = 1; i <= len; i++) rk[sa[i]] = i;
for (int i = 1; i <= len; i++) {
if (rk[i] == 1) continue;
if (k) --k;
int j = sa[rk[i] - 1];
while (j + k <= len && i + k <= len && s[i + k] == s[j + k]) k++;
height[rk[i]] = k;
}
}
}
正确的:
namespace SA {
int len;
int sa[MAXN], rk[MAXN << 1], oldrk[MAXN << 1], id[MAXN], cnt[MAXN];
void run(char s[], int _len) { // call: run(str, strlen(str+1));
len = _len;
int m = max(len, 300);
// memset(cnt, 0, sizeof(cnt));
for (int i = 0; i <= m; i++) cnt[i] = 0;
for (int i = 1; i <= len; i++) ++cnt[rk[i] = s[i]];
for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
for (int i = len; i >= 1; i--) sa[cnt[rk[i]]--] = i;
for (int i = len+1; i <= (len<<1); i++) oldrk[i] = rk[i] = 0; // 这里!
for (int w = 1; w <= len; w <<= 1) {
// memset(cnt, 0, sizeof(cnt));
for (int i = 0; i <= m; i++) cnt[i] = 0;
for (int i = 1; i <= len; i++) id[i] = sa[i];
for (int i = 1; i <= len; i++) ++cnt[rk[id[i] + w]];
for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
for (int i = len; i >= 1; i--) sa[cnt[rk[id[i] + w]]--] = id[i];
for (int i = 0; i <= m; i++) cnt[i] = 0;
// memset(cnt, 0, sizeof(cnt));
for (int i = 1; i <= len; i++) id[i] = sa[i];
for (int i = 1; i <= len; i++) ++cnt[rk[id[i]]];
for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
for (int i = len; i >= 1; i--) sa[cnt[rk[id[i]]]--] = id[i];
// memcpy(oldrk, rk, sizeof(rk));
for (int i = 0; i <= len; i++) oldrk[i] = rk[i];
for (int p = 0, i = 1; i <= len; i++) {
if (oldrk[sa[i]] == oldrk[sa[i - 1]] && oldrk[sa[i] + w] == oldrk[sa[i - 1] + w]) rk[sa[i]] = p;
else rk[sa[i]] = ++p;
}
}
}
void get_height(char s[]) { // step2 call: get_height(str)
int k = 0;
for (int i = 1; i <= len; i++) rk[sa[i]] = i;
for (int i = 1; i <= len; i++) {
if (rk[i] == 1) continue;
if (k) --k;
int j = sa[rk[i] - 1];
while (j + k <= len && i + k <= len && s[i + k] == s[j + k]) k++;
height[rk[i]] = k;
}
}
}