From 2ddf97ee0467ba68a244476f29077fd45c6520af Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Sun, 25 Jan 2026 14:49:56 -0700 Subject: [PATCH 01/24] Modify suffix array algorithm to use K-based sorting Refactor suffix array construction to use a base K for sorting. --- library/strings/suffix_array/suffix_array_short.hpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/library/strings/suffix_array/suffix_array_short.hpp b/library/strings/suffix_array/suffix_array_short.hpp index cb0a7f34..5d468d38 100644 --- a/library/strings/suffix_array/suffix_array_short.hpp +++ b/library/strings/suffix_array/suffix_array_short.hpp @@ -11,13 +11,18 @@ //! @time O(n * log^2(n)) //! @space O(n) auto sa_short(const auto& s) { + const int K = 4; int n = sz(s); vi sa(n), sa_inv(all(s)), lcp(n - 1); iota(all(sa), 0); - for (int k = 1; k <= n; k *= 2) { + for (int j = 1; j <= n; j *= K) { vi x(sa_inv); auto proj = [&](int i) { - return pair(x[i], i + k < n ? x[i + k] : -1); + array res; + rep (k, 0, K) + res[k] = i + j * k < n ? x[i + j * k] : -1; + return res; + //return pair(x[i], i + j < n ? x[i + j] : -1); }; ranges::sort(sa, {}, proj); sa_inv[sa[0]] = 0; From 0119dd6b0ab06089efc661306085fbbc199e43dc Mon Sep 17 00:00:00 2001 From: GitHub Date: Sun, 25 Jan 2026 22:01:25 +0000 Subject: [PATCH 02/24] [auto-verifier] verify commit 2ddf97ee0467ba68a244476f29077fd45c6520af --- .verify-helper/timestamps.remote.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.verify-helper/timestamps.remote.json b/.verify-helper/timestamps.remote.json index 888d63a0..d6c40c75 100644 --- a/.verify-helper/timestamps.remote.json +++ b/.verify-helper/timestamps.remote.json @@ -106,7 +106,7 @@ "tests/library_checker_aizu_tests/monotonic_stack_related/count_rectangles.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/monotonic_stack_related/max_rect_histogram.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/strings/kmp.test.cpp": "2025-08-05 19:19:23 -0600", -"tests/library_checker_aizu_tests/strings/lcp_array.test.cpp": "2025-08-05 19:19:23 -0600", +"tests/library_checker_aizu_tests/strings/lcp_array.test.cpp": "2026-01-25 14:49:56 -0700", "tests/library_checker_aizu_tests/strings/lcp_query_palindrome.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/strings/lcp_query_zfunc.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/strings/lcs_dp.test.cpp": "2025-08-05 19:19:23 -0600", @@ -119,7 +119,7 @@ "tests/library_checker_aizu_tests/strings/sa_sort_pairs.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/strings/single_matching_bs.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/strings/suffix_array.test.cpp": "2026-01-18 11:15:41 +0000", -"tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp": "2025-08-05 19:19:23 -0600", +"tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp": "2026-01-25 14:49:56 -0700", "tests/library_checker_aizu_tests/strings/trie.test.cpp": "2026-01-17 12:38:18 -0700", "tests/library_checker_aizu_tests/strings/wildcard_pattern_matching.test.cpp": "2025-08-05 19:19:23 -0600", "tests/library_checker_aizu_tests/trees/count_paths_per_length.test.cpp": "2025-12-11 21:47:53 +0000", From 711cb9b1b87b2589cb24ee0a01714b46711ec12f Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Sun, 25 Jan 2026 18:47:22 -0700 Subject: [PATCH 03/24] Update suffix array test to include LCP verification --- .../strings/suffix_array_short.test.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp b/tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp index bb25b839..e63ed076 100644 --- a/tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp +++ b/tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp @@ -9,11 +9,22 @@ int main() { cin.tie(0)->sync_with_stdio(0); string s; cin >> s; - auto [sa, sa_inv, _] = sa_short(vi(all(s))); - for (int i = 0; i < sz(s); i++) { + auto [sa, sa_inv, lcp] = sa_short(vi(all(s))); + rep (i, 0, sz(s)) { assert(sa[sa_inv[i]] == i); assert(sa_inv[sa[i]] == i); } + vi lcp_kasai(sz(s) - 1); + int sz = 0; + rep(i, 0, n) { + if (sz > 0) sz--; + if (sa_inv[i] == 0) continue; + for (int j = sa[sa_inv[i] - 1]; + max(i, j) + sz < n && s[i + sz] == s[j + sz];) + sz++; + lcp_kasai[sa_inv[i] - 1] = sz; + } + assert(lcp == lcp_kasai); for (int val : sa) cout << val << " "; cout << '\n'; } From 22c7c081ba97cbdc1de931781db79cb65137a911 Mon Sep 17 00:00:00 2001 From: GitHub Date: Mon, 26 Jan 2026 01:48:21 +0000 Subject: [PATCH 04/24] [auto-verifier] verify commit 711cb9b1b87b2589cb24ee0a01714b46711ec12f --- .verify-helper/timestamps.remote.json | 1 - 1 file changed, 1 deletion(-) diff --git a/.verify-helper/timestamps.remote.json b/.verify-helper/timestamps.remote.json index d6c40c75..a4a95595 100644 --- a/.verify-helper/timestamps.remote.json +++ b/.verify-helper/timestamps.remote.json @@ -119,7 +119,6 @@ "tests/library_checker_aizu_tests/strings/sa_sort_pairs.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/strings/single_matching_bs.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/strings/suffix_array.test.cpp": "2026-01-18 11:15:41 +0000", -"tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp": "2026-01-25 14:49:56 -0700", "tests/library_checker_aizu_tests/strings/trie.test.cpp": "2026-01-17 12:38:18 -0700", "tests/library_checker_aizu_tests/strings/wildcard_pattern_matching.test.cpp": "2025-08-05 19:19:23 -0600", "tests/library_checker_aizu_tests/trees/count_paths_per_length.test.cpp": "2025-12-11 21:47:53 +0000", From 4ee9358653f23b1e2e91e098ad5aae9909dcfb9c Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Sun, 25 Jan 2026 18:49:16 -0700 Subject: [PATCH 05/24] Fix loop range in suffix array test --- .../strings/suffix_array_short.test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp b/tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp index e63ed076..f07068ae 100644 --- a/tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp +++ b/tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp @@ -16,7 +16,7 @@ int main() { } vi lcp_kasai(sz(s) - 1); int sz = 0; - rep(i, 0, n) { + rep(i, 0, sz(s)) { if (sz > 0) sz--; if (sa_inv[i] == 0) continue; for (int j = sa[sa_inv[i] - 1]; From 2cb9676df77940c59eacea9665150f6e707c96b7 Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Sun, 25 Jan 2026 18:51:08 -0700 Subject: [PATCH 06/24] Fix condition in suffix array test case --- .../strings/suffix_array_short.test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp b/tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp index f07068ae..850466a7 100644 --- a/tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp +++ b/tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp @@ -20,7 +20,7 @@ int main() { if (sz > 0) sz--; if (sa_inv[i] == 0) continue; for (int j = sa[sa_inv[i] - 1]; - max(i, j) + sz < n && s[i + sz] == s[j + sz];) + max(i, j) + sz < sz(s) && s[i + sz] == s[j + sz];) sz++; lcp_kasai[sa_inv[i] - 1] = sz; } From ed8ee918de299087bc1d7ec8b0092efb73320a01 Mon Sep 17 00:00:00 2001 From: GitHub Date: Mon, 26 Jan 2026 01:58:33 +0000 Subject: [PATCH 07/24] [auto-verifier] verify commit 2cb9676df77940c59eacea9665150f6e707c96b7 --- .verify-helper/timestamps.remote.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.verify-helper/timestamps.remote.json b/.verify-helper/timestamps.remote.json index a4a95595..ec5b73ec 100644 --- a/.verify-helper/timestamps.remote.json +++ b/.verify-helper/timestamps.remote.json @@ -119,6 +119,7 @@ "tests/library_checker_aizu_tests/strings/sa_sort_pairs.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/strings/single_matching_bs.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/strings/suffix_array.test.cpp": "2026-01-18 11:15:41 +0000", +"tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp": "2026-01-25 18:51:08 -0700", "tests/library_checker_aizu_tests/strings/trie.test.cpp": "2026-01-17 12:38:18 -0700", "tests/library_checker_aizu_tests/strings/wildcard_pattern_matching.test.cpp": "2025-08-05 19:19:23 -0600", "tests/library_checker_aizu_tests/trees/count_paths_per_length.test.cpp": "2025-12-11 21:47:53 +0000", From 9f834a9ff9520f1540a6ec0e9ea55a71e18e07dc Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Sun, 25 Jan 2026 19:12:53 -0700 Subject: [PATCH 08/24] Update suffix_array_short.hpp --- .../suffix_array/suffix_array_short.hpp | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/library/strings/suffix_array/suffix_array_short.hpp b/library/strings/suffix_array/suffix_array_short.hpp index 5d468d38..619b238c 100644 --- a/library/strings/suffix_array/suffix_array_short.hpp +++ b/library/strings/suffix_array/suffix_array_short.hpp @@ -11,32 +11,32 @@ //! @time O(n * log^2(n)) //! @space O(n) auto sa_short(const auto& s) { - const int K = 4; - int n = sz(s); + const int n = sz(s), K = 4; vi sa(n), sa_inv(all(s)), lcp(n - 1); iota(all(sa), 0); for (int j = 1; j <= n; j *= K) { - vi x(sa_inv); - auto proj = [&](int i) { + vi x(sa_inv), y(lcp); + auto f = [&](int i) { array res; rep (k, 0, K) res[k] = i + j * k < n ? x[i + j * k] : -1; return res; - //return pair(x[i], i + j < n ? x[i + j] : -1); }; - ranges::sort(sa, {}, proj); + ranges::sort(sa, {}, f); sa_inv[sa[0]] = 0; - rep(i, 1, n) sa_inv[sa[i]] = - sa_inv[sa[i - 1]] + (proj(sa[i - 1]) != proj(sa[i])); - } - int sz = 0; - rep(i, 0, n) { - if (sz > 0) sz--; - if (sa_inv[i] == 0) continue; - for (int j = sa[sa_inv[i] - 1]; - max(i, j) + sz < n && s[i + sz] == s[j + sz];) - sz++; - lcp[sa_inv[i] - 1] = sz; + rep(i, 0, n - 1) { + sa_inv[sa[i + 1]] = sa_inv[sa[i]]; + if (f(sa[i + 1]) != f(sa[i])) { + sa_inv[sa[i]]++; + rep (k, 0, K) { + if (f(sa[i + 1])[k] != f(sa[i])[k]) { + lcp[i] = j * k + (i + j * k < n ? y[i + j * k] : 0); + } + } + } else { + lcp[i] = j * K; + } + } } return tuple{sa, sa_inv, lcp}; } From 76cc0f94bfe9ff20d2e451fbb2644bca6510eb8f Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Sun, 25 Jan 2026 19:18:02 -0700 Subject: [PATCH 09/24] Fix suffix array index handling in LCP calculation --- library/strings/suffix_array/suffix_array_short.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/strings/suffix_array/suffix_array_short.hpp b/library/strings/suffix_array/suffix_array_short.hpp index 619b238c..c7b15b25 100644 --- a/library/strings/suffix_array/suffix_array_short.hpp +++ b/library/strings/suffix_array/suffix_array_short.hpp @@ -27,10 +27,10 @@ auto sa_short(const auto& s) { rep(i, 0, n - 1) { sa_inv[sa[i + 1]] = sa_inv[sa[i]]; if (f(sa[i + 1]) != f(sa[i])) { - sa_inv[sa[i]]++; + sa_inv[sa[i + 1]]++; rep (k, 0, K) { if (f(sa[i + 1])[k] != f(sa[i])[k]) { - lcp[i] = j * k + (i + j * k < n ? y[i + j * k] : 0); + lcp[i] = j * k + (sa[i] + j * k < n ? y[sa_inv[sa[i] + j * k]] : 0); } } } else { From 3ffb893e1dd4e162f3d612b92f334630dade96ee Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Sun, 25 Jan 2026 19:26:17 -0700 Subject: [PATCH 10/24] Fix LCP calculation in suffix array implementation --- library/strings/suffix_array/suffix_array_short.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/strings/suffix_array/suffix_array_short.hpp b/library/strings/suffix_array/suffix_array_short.hpp index c7b15b25..286ec530 100644 --- a/library/strings/suffix_array/suffix_array_short.hpp +++ b/library/strings/suffix_array/suffix_array_short.hpp @@ -30,7 +30,7 @@ auto sa_short(const auto& s) { sa_inv[sa[i + 1]]++; rep (k, 0, K) { if (f(sa[i + 1])[k] != f(sa[i])[k]) { - lcp[i] = j * k + (sa[i] + j * k < n ? y[sa_inv[sa[i] + j * k]] : 0); + lcp[i] = j * k + (sa[i] + j * k < n ? y[x[sa[i] + j * k]] : 0); } } } else { From 68349dd6c1704b2bd8212ffcd7dbb44668d989cf Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Sun, 25 Jan 2026 19:31:42 -0700 Subject: [PATCH 11/24] Fix lcp calculation in suffix_array_short.hpp --- library/strings/suffix_array/suffix_array_short.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/library/strings/suffix_array/suffix_array_short.hpp b/library/strings/suffix_array/suffix_array_short.hpp index 286ec530..02db1ccd 100644 --- a/library/strings/suffix_array/suffix_array_short.hpp +++ b/library/strings/suffix_array/suffix_array_short.hpp @@ -31,6 +31,7 @@ auto sa_short(const auto& s) { rep (k, 0, K) { if (f(sa[i + 1])[k] != f(sa[i])[k]) { lcp[i] = j * k + (sa[i] + j * k < n ? y[x[sa[i] + j * k]] : 0); + break; } } } else { From b2f1c6d046c67d95dae4c355a1b2d330a65a7e51 Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Sun, 25 Jan 2026 19:40:12 -0700 Subject: [PATCH 12/24] Update LCP calculation to use min function --- library/strings/suffix_array/suffix_array_short.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/strings/suffix_array/suffix_array_short.hpp b/library/strings/suffix_array/suffix_array_short.hpp index 02db1ccd..98c9060e 100644 --- a/library/strings/suffix_array/suffix_array_short.hpp +++ b/library/strings/suffix_array/suffix_array_short.hpp @@ -35,7 +35,7 @@ auto sa_short(const auto& s) { } } } else { - lcp[i] = j * K; + lcp[i] = min({j * K, n - sa[i], n - sa[i + 1]}); } } } From 453472837863f406f47439b092944553aa54e10b Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Sun, 25 Jan 2026 20:10:08 -0700 Subject: [PATCH 13/24] Refactor suffix array sorting and LCP computation --- .../suffix_array/suffix_array_short.hpp | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/library/strings/suffix_array/suffix_array_short.hpp b/library/strings/suffix_array/suffix_array_short.hpp index 98c9060e..b016723e 100644 --- a/library/strings/suffix_array/suffix_array_short.hpp +++ b/library/strings/suffix_array/suffix_array_short.hpp @@ -16,27 +16,22 @@ auto sa_short(const auto& s) { iota(all(sa), 0); for (int j = 1; j <= n; j *= K) { vi x(sa_inv), y(lcp); - auto f = [&](int i) { - array res; - rep (k, 0, K) - res[k] = i + j * k < n ? x[i + j * k] : -1; - return res; + int val; + auto cmp = [&](int i1, int i2) { + val = 0; + rep (k, 0, K) { + int a = i1 + j * k < n ? x[i1 + j * k] : -1; + int b = i2 + j * k < n ? x[i2 + j * k] : -1; + if (a != b) return val += y[b], a < b; + val += j; + } + return false; }; - ranges::sort(sa, {}, f); + ranges::sort(sa, cmp); sa_inv[sa[0]] = 0; rep(i, 0, n - 1) { - sa_inv[sa[i + 1]] = sa_inv[sa[i]]; - if (f(sa[i + 1]) != f(sa[i])) { - sa_inv[sa[i + 1]]++; - rep (k, 0, K) { - if (f(sa[i + 1])[k] != f(sa[i])[k]) { - lcp[i] = j * k + (sa[i] + j * k < n ? y[x[sa[i] + j * k]] : 0); - break; - } - } - } else { - lcp[i] = min({j * K, n - sa[i], n - sa[i + 1]}); - } + sa_inv[sa[i + 1]] = sa_inv[sa[i]] + cmp(sa[i], sa[i + 1]); + lcp[i] = val; } } return tuple{sa, sa_inv, lcp}; From a637445560dd4ae02b3404388750843d7f269660 Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Sun, 25 Jan 2026 20:15:05 -0700 Subject: [PATCH 14/24] Improve suffix array comparison handling Refactor comparison logic to handle -1 case in suffix array. --- library/strings/suffix_array/suffix_array_short.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/strings/suffix_array/suffix_array_short.hpp b/library/strings/suffix_array/suffix_array_short.hpp index b016723e..d329ca2f 100644 --- a/library/strings/suffix_array/suffix_array_short.hpp +++ b/library/strings/suffix_array/suffix_array_short.hpp @@ -22,7 +22,11 @@ auto sa_short(const auto& s) { rep (k, 0, K) { int a = i1 + j * k < n ? x[i1 + j * k] : -1; int b = i2 + j * k < n ? x[i2 + j * k] : -1; - if (a != b) return val += y[b], a < b; + if (a != b) { + if (a != -1) val += y[a]; + else val = n - i1; + return a < b; + } val += j; } return false; From d282ec72609b8fca2a37660f85ab093695ae63da Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Sun, 25 Jan 2026 20:22:35 -0700 Subject: [PATCH 15/24] Add assertion for index 'a' in suffix array Add assertion to ensure 'a' is within bounds before accessing 'y'. --- library/strings/suffix_array/suffix_array_short.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/strings/suffix_array/suffix_array_short.hpp b/library/strings/suffix_array/suffix_array_short.hpp index d329ca2f..06d83442 100644 --- a/library/strings/suffix_array/suffix_array_short.hpp +++ b/library/strings/suffix_array/suffix_array_short.hpp @@ -23,7 +23,7 @@ auto sa_short(const auto& s) { int a = i1 + j * k < n ? x[i1 + j * k] : -1; int b = i2 + j * k < n ? x[i2 + j * k] : -1; if (a != b) { - if (a != -1) val += y[a]; + if (a != -1) assert(a Date: Sun, 25 Jan 2026 20:33:33 -0700 Subject: [PATCH 16/24] Refactor conditionals for clarity in suffix_array_short.hpp --- library/strings/suffix_array/suffix_array_short.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/strings/suffix_array/suffix_array_short.hpp b/library/strings/suffix_array/suffix_array_short.hpp index 06d83442..80b75f35 100644 --- a/library/strings/suffix_array/suffix_array_short.hpp +++ b/library/strings/suffix_array/suffix_array_short.hpp @@ -23,8 +23,9 @@ auto sa_short(const auto& s) { int a = i1 + j * k < n ? x[i1 + j * k] : -1; int b = i2 + j * k < n ? x[i2 + j * k] : -1; if (a != b) { - if (a != -1) assert(a Date: Sun, 25 Jan 2026 21:38:35 -0700 Subject: [PATCH 17/24] Update suffix_array_short.hpp --- library/strings/suffix_array/suffix_array_short.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/strings/suffix_array/suffix_array_short.hpp b/library/strings/suffix_array/suffix_array_short.hpp index 80b75f35..846a512b 100644 --- a/library/strings/suffix_array/suffix_array_short.hpp +++ b/library/strings/suffix_array/suffix_array_short.hpp @@ -15,7 +15,8 @@ auto sa_short(const auto& s) { vi sa(n), sa_inv(all(s)), lcp(n - 1); iota(all(sa), 0); for (int j = 1; j <= n; j *= K) { - vi x(sa_inv), y(lcp); + vi x(sa_inv), y(n, -1); + rep (i, 0, n - 1) y[sa[i]] = lcp[i]; int val; auto cmp = [&](int i1, int i2) { val = 0; @@ -23,9 +24,7 @@ auto sa_short(const auto& s) { int a = i1 + j * k < n ? x[i1 + j * k] : -1; int b = i2 + j * k < n ? x[i2 + j * k] : -1; if (a != b) { - if (a != -1) { - if(a Date: Tue, 27 Jan 2026 10:57:37 -0700 Subject: [PATCH 18/24] fix --- .../suffix_array/suffix_array_short.hpp | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/library/strings/suffix_array/suffix_array_short.hpp b/library/strings/suffix_array/suffix_array_short.hpp index 846a512b..2fd83767 100644 --- a/library/strings/suffix_array/suffix_array_short.hpp +++ b/library/strings/suffix_array/suffix_array_short.hpp @@ -7,36 +7,35 @@ //! vi s_vec; //! auto [sa1, sa_inv1, lcp1] = sa_short(s_vec); //! @endcode -//! runs in ~1.5s for 5e5 +//! runs in ~0.5s for 5e5 //! @time O(n * log^2(n)) //! @space O(n) auto sa_short(const auto& s) { - const int n = sz(s), K = 4; + const int n = sz(s), K = 6; vi sa(n), sa_inv(all(s)), lcp(n - 1); iota(all(sa), 0); for (int j = 1; j <= n; j *= K) { - vi x(sa_inv), y(n, -1); - rep (i, 0, n - 1) y[sa[i]] = lcp[i]; - int val; + vi x(sa_inv); auto cmp = [&](int i1, int i2) { - val = 0; rep (k, 0, K) { int a = i1 + j * k < n ? x[i1 + j * k] : -1; int b = i2 + j * k < n ? x[i2 + j * k] : -1; - if (a != b) { - if (a != -1) val += y[i1 + j * k]; - return a < b; - } - val += j; + if (a != b) return a < b; } return false; }; - ranges::sort(sa, cmp); + sort(all(sa), cmp); sa_inv[sa[0]] = 0; - rep(i, 0, n - 1) { - sa_inv[sa[i + 1]] = sa_inv[sa[i]] + cmp(sa[i], sa[i + 1]); - lcp[i] = val; - } + rep(i, 1, n) + sa_inv[sa[i]] = sa_inv[sa[i - 1]] + cmp(sa[i - 1], sa[i]); + } + int sz = 0; + rep(i, 0, n) { + if (sz > 0) sz--; + if (sa_inv[i] == 0) continue; + int j = sa[sa_inv[i] - 1]; + while(max(i, j) + sz < n && s[i + sz] == s[j + sz];) sz++; + lcp[sa_inv[i] - 1] = sz; } return tuple{sa, sa_inv, lcp}; } From c07326088ab1b22ec8e2eb29851bb80e93912be6 Mon Sep 17 00:00:00 2001 From: GitHub Date: Tue, 27 Jan 2026 17:58:55 +0000 Subject: [PATCH 19/24] [auto-verifier] verify commit 8fd2384bbc4cab5f257615e5bb7d28512541961a --- .verify-helper/timestamps.remote.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/.verify-helper/timestamps.remote.json b/.verify-helper/timestamps.remote.json index ec5b73ec..76db5bf5 100644 --- a/.verify-helper/timestamps.remote.json +++ b/.verify-helper/timestamps.remote.json @@ -106,7 +106,6 @@ "tests/library_checker_aizu_tests/monotonic_stack_related/count_rectangles.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/monotonic_stack_related/max_rect_histogram.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/strings/kmp.test.cpp": "2025-08-05 19:19:23 -0600", -"tests/library_checker_aizu_tests/strings/lcp_array.test.cpp": "2026-01-25 14:49:56 -0700", "tests/library_checker_aizu_tests/strings/lcp_query_palindrome.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/strings/lcp_query_zfunc.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/strings/lcs_dp.test.cpp": "2025-08-05 19:19:23 -0600", @@ -119,7 +118,6 @@ "tests/library_checker_aizu_tests/strings/sa_sort_pairs.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/strings/single_matching_bs.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/strings/suffix_array.test.cpp": "2026-01-18 11:15:41 +0000", -"tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp": "2026-01-25 18:51:08 -0700", "tests/library_checker_aizu_tests/strings/trie.test.cpp": "2026-01-17 12:38:18 -0700", "tests/library_checker_aizu_tests/strings/wildcard_pattern_matching.test.cpp": "2025-08-05 19:19:23 -0600", "tests/library_checker_aizu_tests/trees/count_paths_per_length.test.cpp": "2025-12-11 21:47:53 +0000", From d263a75e471d3f7ce947ef7afb33db4adac6e80d Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Tue, 27 Jan 2026 11:01:32 -0700 Subject: [PATCH 20/24] fix --- .../strings/suffix_array/suffix_array_short.hpp | 14 +++++++------- .../strings/suffix_array_short.test.cpp | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/strings/suffix_array/suffix_array_short.hpp b/library/strings/suffix_array/suffix_array_short.hpp index 2fd83767..c65ac8d6 100644 --- a/library/strings/suffix_array/suffix_array_short.hpp +++ b/library/strings/suffix_array/suffix_array_short.hpp @@ -17,7 +17,7 @@ auto sa_short(const auto& s) { for (int j = 1; j <= n; j *= K) { vi x(sa_inv); auto cmp = [&](int i1, int i2) { - rep (k, 0, K) { + rep(k, 0, K) { int a = i1 + j * k < n ? x[i1 + j * k] : -1; int b = i2 + j * k < n ? x[i2 + j * k] : -1; if (a != b) return a < b; @@ -26,16 +26,16 @@ auto sa_short(const auto& s) { }; sort(all(sa), cmp); sa_inv[sa[0]] = 0; - rep(i, 1, n) - sa_inv[sa[i]] = sa_inv[sa[i - 1]] + cmp(sa[i - 1], sa[i]); + rep(i, 1, n) sa_inv[sa[i]] = + sa_inv[sa[i - 1]] + cmp(sa[i - 1], sa[i]); } - int sz = 0; + int l = 0; rep(i, 0, n) { - if (sz > 0) sz--; + if (l > 0) l--; if (sa_inv[i] == 0) continue; int j = sa[sa_inv[i] - 1]; - while(max(i, j) + sz < n && s[i + sz] == s[j + sz];) sz++; - lcp[sa_inv[i] - 1] = sz; + while (max(i, j) + l < n && s[i + l] == s[j + l]) l++; + lcp[sa_inv[i] - 1] = l; } return tuple{sa, sa_inv, lcp}; } diff --git a/tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp b/tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp index 850466a7..59685667 100644 --- a/tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp +++ b/tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp @@ -10,7 +10,7 @@ int main() { string s; cin >> s; auto [sa, sa_inv, lcp] = sa_short(vi(all(s))); - rep (i, 0, sz(s)) { + rep(i, 0, sz(s)) { assert(sa[sa_inv[i]] == i); assert(sa_inv[sa[i]] == i); } From ae6f5ee1674ad41a18652c9413fd77d9de6fd8ff Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Tue, 27 Jan 2026 11:03:58 -0700 Subject: [PATCH 21/24] nameing nit --- library/strings/suffix_array/suffix_array_short.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/strings/suffix_array/suffix_array_short.hpp b/library/strings/suffix_array/suffix_array_short.hpp index c65ac8d6..1fd96d2f 100644 --- a/library/strings/suffix_array/suffix_array_short.hpp +++ b/library/strings/suffix_array/suffix_array_short.hpp @@ -11,13 +11,13 @@ //! @time O(n * log^2(n)) //! @space O(n) auto sa_short(const auto& s) { - const int n = sz(s), K = 6; + const int n = sz(s), x = 6; vi sa(n), sa_inv(all(s)), lcp(n - 1); iota(all(sa), 0); - for (int j = 1; j <= n; j *= K) { + for (int j = 1; j <= n; j *= x) { vi x(sa_inv); auto cmp = [&](int i1, int i2) { - rep(k, 0, K) { + rep(k, 0, x) { int a = i1 + j * k < n ? x[i1 + j * k] : -1; int b = i2 + j * k < n ? x[i2 + j * k] : -1; if (a != b) return a < b; From 82db04b4161343a7822eb7c2a64f55faaa23df91 Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Tue, 27 Jan 2026 11:07:54 -0700 Subject: [PATCH 22/24] fixes --- library/strings/suffix_array/suffix_array_short.hpp | 6 +++--- tests/scripts/grep_clangformat_cppcheck.sh | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/library/strings/suffix_array/suffix_array_short.hpp b/library/strings/suffix_array/suffix_array_short.hpp index 1fd96d2f..4bfcc087 100644 --- a/library/strings/suffix_array/suffix_array_short.hpp +++ b/library/strings/suffix_array/suffix_array_short.hpp @@ -11,13 +11,13 @@ //! @time O(n * log^2(n)) //! @space O(n) auto sa_short(const auto& s) { - const int n = sz(s), x = 6; + const int n = sz(s), b = 6; vi sa(n), sa_inv(all(s)), lcp(n - 1); iota(all(sa), 0); - for (int j = 1; j <= n; j *= x) { + for (int j = 1; j <= n; j *= b) { vi x(sa_inv); auto cmp = [&](int i1, int i2) { - rep(k, 0, x) { + rep(k, 0, b) { int a = i1 + j * k < n ? x[i1 + j * k] : -1; int b = i2 + j * k < n ? x[i2 + j * k] : -1; if (a != b) return a < b; diff --git a/tests/scripts/grep_clangformat_cppcheck.sh b/tests/scripts/grep_clangformat_cppcheck.sh index 56c9863f..90f6fdb4 100755 --- a/tests/scripts/grep_clangformat_cppcheck.sh +++ b/tests/scripts/grep_clangformat_cppcheck.sh @@ -16,9 +16,6 @@ grep --extended-regexp "template\s? Date: Tue, 27 Jan 2026 11:09:28 -0700 Subject: [PATCH 23/24] copy change here too --- library/strings/suffix_array/suffix_array.hpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/library/strings/suffix_array/suffix_array.hpp b/library/strings/suffix_array/suffix_array.hpp index 8ce1278f..cdeda4ec 100644 --- a/library/strings/suffix_array/suffix_array.hpp +++ b/library/strings/suffix_array/suffix_array.hpp @@ -57,14 +57,13 @@ auto get_sa(const auto& s, int max_num) { } if (max_num == n) break; } - int sz = 0; + int l = 0; rep(i, 0, n) { - if (sz > 0) sz--; + if (l > 0) l--; if (sa_inv[i] == 0) continue; - for (int j = sa[sa_inv[i] - 1]; - max(i, j) + sz < n && s[i + sz] == s[j + sz];) - sz++; - lcp[sa_inv[i] - 1] = sz; + int j = sa[sa_inv[i] - 1]; + while (max(i, j) + l < n && s[i + l] == s[j + l]) l++; + lcp[sa_inv[i] - 1] = l; } return tuple{sa, sa_inv, lcp}; } From 2cad9935c4374ec08693cd71b5b3c5327e94cdc4 Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Tue, 27 Jan 2026 11:10:03 -0700 Subject: [PATCH 24/24] fix --- tests/.config/.cppcheck_suppression_list | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/.config/.cppcheck_suppression_list b/tests/.config/.cppcheck_suppression_list index 21d6bced..fbdc851f 100644 --- a/tests/.config/.cppcheck_suppression_list +++ b/tests/.config/.cppcheck_suppression_list @@ -40,7 +40,7 @@ syntaxError:../library/loops/supermasks.hpp:8 syntaxError:../library/math/prime_sieve/mobius.hpp:6 syntaxError:../library/trees/lca_rmq/iterate_subtree.hpp:6 knownConditionTrueFalse:../library/strings/suffix_array/suffix_array.hpp:62 -knownConditionTrueFalse:../library/strings/suffix_array/suffix_array_short.hpp:29 +knownConditionTrueFalse:../library/strings/suffix_array/suffix_array_short.hpp:34 knownConditionTrueFalse:../library/dsu/kruskal_tree.hpp:15 knownConditionTrueFalse:../library/dsu/dsu.hpp:11 constVariable:../kactl/content/numerical/NumberTheoreticTransform.h:30