Hướng giải của Đếm palindrome con (Manacher)
Nhớ rằng hướng dẫn giải này chỉ nên sử dụng khi bế tắc, và tuyệt đối không nên sao chép mã nguồn kèm theo. Hãy tôn trọng tác giả bài tập và người viết hướng dẫn giải.
Nộp mã nguồn lời giải chính thức trước khi giải bài tập đó có thể khiến bạn bị ban.
Nộp mã nguồn lời giải chính thức trước khi giải bài tập đó có thể khiến bạn bị ban.
Tác giả:
Lời giải: Đếm palindrome con bằng Manacher
Phân tích
Với mỗi tâm i trong xâu đã biến đổi, bán kính palindrome p[i] cho biết có p[i] palindrome tại tâm đó (bán kính 1, 2, ..., p[i]). Tổng tất cả palindrome là \(\sum_i \left\lceil \frac{p[i]}{2} \right\rceil\) (làm tròn lên vì mỗi palindrome ở xâu gốc tương ứng 2 palindrome ở xâu biến đổi: chẵn và lẻ).
Độ phức tạp
- Thời gian: O(N)
- Không gian: O(N)
Code mẫu C++
#include <bits/stdc++.h>
using namespace std;
int main() {
string s;
cin >> s;
int n = s.size();
// Bien doi: chen '#' giua cac ky tu
string t = "#";
for (char c : s) {
t += c;
t += '#';
}
int m = t.size();
vector<int> p(m, 0);
int center = 0, right = 0;
for (int i = 0; i < m; i++) {
if (i < right) {
p[i] = min(right - i, p[2 * center - i]);
}
while (i - p[i] - 1 >= 0 && i + p[i] + 1 < m && t[i - p[i] - 1] == t[i + p[i] + 1]) {
p[i]++;
}
if (i + p[i] > right) {
center = i;
right = i + p[i];
}
}
// Tong so palindrome: moi p[i] "luu tru" (p[i] + 1) / 2 palindrome trong S
long long total = 0;
for (int i = 0; i < m; i++) {
total += (p[i] + 1) / 2; // Lam tron len
}
cout << total << endl;
return 0;
}
Giải thích
- Mỗi palindrome ở xâu gốc có 2 palindrome tương ứng trong xâu biến đổi (chẵn vs lẻ).
(p[i] + 1) / 2cho số palindrome ở xâu gốc với tâm tại vị trí tương ứng.- Ví dụ
S = "abac", biến đổi thành"#a#b#a#c#", các palindrome được đếm đúng 5 (a, b, a, c, aba).
Nhận xét