From aa9704c34629d95c095a0d6d59b552ce59ea600d Mon Sep 17 00:00:00 2001 From: hitonanode <32937551+hitonanode@users.noreply.github.com> Date: Sat, 29 Nov 2025 14:52:59 +0900 Subject: [PATCH 1/2] fix manacher --- string/manacher.hpp | 7 +++++-- string/manacher.md | 5 +++++ string/test/manacher.yuki3392.test.cpp | 22 ++++++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 string/test/manacher.yuki3392.test.cpp diff --git a/string/manacher.hpp b/string/manacher.hpp index 62d811d7..7e38e1f2 100644 --- a/string/manacher.hpp +++ b/string/manacher.hpp @@ -3,7 +3,6 @@ #include #include -// CUT begin // Manacher's Algorithm: radius of palindromes // Input: std::string or std::vector of length N // Output: std::vector of size N @@ -30,8 +29,13 @@ std::vector manacher(const std::string &S) { return manacher(v); } +// Find maximal palindrome length for each center +// input: array of length N +// output: array of length N * 2 - 1 template std::vector> enumerate_palindromes(const std::vector &vec) { + if (vec.empty()) return {}; + std::vector v; const int N = vec.size(); for (int i = 0; i < N - 1; i++) { @@ -52,7 +56,6 @@ std::vector> enumerate_palindromes(const std::vector &vec } return ret; } - std::vector> enumerate_palindromes(const std::string &S) { std::vector v(S.size()); for (int i = 0; i < int(S.size()); i++) v[i] = S[i]; diff --git a/string/manacher.md b/string/manacher.md index 2e15edac..827ee13f 100644 --- a/string/manacher.md +++ b/string/manacher.md @@ -16,6 +16,11 @@ for (auto [l, r] : palindromes) { } ``` +## 問題例 + +- [Enumerate Palindromes](https://judge.yosupo.jp/problem/enumerate_palindromes) +- [No.3392 Count 23578 Sequence - yukicoder](https://yukicoder.me/problems/no/3392) + ## 文献 - [1] G. Manacher, "A new linear-time "on-line" algorithm for finding the smallest initial palindrome of a string", Journal of the ACM, 22 (3), 346-351, 1975. diff --git a/string/test/manacher.yuki3392.test.cpp b/string/test/manacher.yuki3392.test.cpp new file mode 100644 index 00000000..21fe81e3 --- /dev/null +++ b/string/test/manacher.yuki3392.test.cpp @@ -0,0 +1,22 @@ +#define PROBLEM "https://yukicoder.me/problems/no/3392" +#include "../manacher.hpp" + +#include +using namespace std; + +int main() { + cin.tie(nullptr), ios::sync_with_stdio(false); + + int N; + cin >> N; + vector A(N); + for (auto &a : A) cin >> a; + + vector D(N - 1); + for (int i = 0; i < N - 1; ++i) D.at(i) = A.at(i + 1) - A.at(i); + + long long ret = N; + for (auto [l, r] : enumerate_palindromes(D)) ret += (r - l + 1) / 2; + + cout << ret << '\n'; +} From 455f8a406f087e96bb5107ef9b3b2088d83451a5 Mon Sep 17 00:00:00 2001 From: hitonanode <32937551+hitonanode@users.noreply.github.com> Date: Mon, 1 Dec 2025 22:55:59 +0900 Subject: [PATCH 2/2] fix existing tests of manacher --- graph/test/shortest_path_dial.yuki1695.test.cpp | 3 ++- graph/test/zero_one_bfs.yuki1695.test.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/graph/test/shortest_path_dial.yuki1695.test.cpp b/graph/test/shortest_path_dial.yuki1695.test.cpp index 3947b758..5f7ebc74 100644 --- a/graph/test/shortest_path_dial.yuki1695.test.cpp +++ b/graph/test/shortest_path_dial.yuki1695.test.cpp @@ -14,6 +14,7 @@ int solve(const string &S, const string &T) { if (!nmatch) return INF; if (T.size() % 2) return INF; auto trev = T; + reverse(trev.begin(), trev.end()); if (trev != T) return INF; shortest_path graph(T.size() + 1); for (int i = 0; i < int(T.size()); ++i) graph.add_edge(i, i + 1, 0); @@ -23,7 +24,7 @@ int solve(const string &S, const string &T) { if ((l + r) % 2 == 0) graph.add_edge(r, (l + r) / 2, 1); } graph.dial(T.size(), nmatch); - return graph.dist[nmatch]; + return std::max(1, graph.dist[nmatch]); } int main() { diff --git a/graph/test/zero_one_bfs.yuki1695.test.cpp b/graph/test/zero_one_bfs.yuki1695.test.cpp index 68fa6573..6a9314f7 100644 --- a/graph/test/zero_one_bfs.yuki1695.test.cpp +++ b/graph/test/zero_one_bfs.yuki1695.test.cpp @@ -14,6 +14,7 @@ int solve(const string &S, const string &T) { if (!nmatch) return INF; if (T.size() % 2) return INF; auto trev = T; + reverse(trev.begin(), trev.end()); if (trev != T) return INF; shortest_path graph(T.size() + 1); for (int i = 0; i < int(T.size()); ++i) graph.add_edge(i, i + 1, 0); @@ -23,7 +24,7 @@ int solve(const string &S, const string &T) { if ((l + r) % 2 == 0) graph.add_edge(r, (l + r) / 2, 1); } graph.zero_one_bfs(T.size(), nmatch); - return graph.dist[nmatch]; + return std::max(1, graph.dist[nmatch]); } int main() {