# Solution Bài 2 TS Subtask 1: - Giới hạn: s ≤ 500 - Hướng giải: Duyệt qua tất cả các chuỗi con có thể có trong chuỗi s và kiểm tra xem chuỗi con đó có đối xứng hay không. Nếu đối xứng, tăng biến đếm lên 1. Subtask 2: - Giới hạn: s ≤ 1000 - Hướng giải: Sử dụng phương pháp DP để xác định các chuỗi con đối xứng. Sử dụng một ma trận isPalindrome[n][n] để lưu trữ thông tin về tính đối xứng của các chuỗi con. Duyệt qua tất cả các độ dài chuỗi con từ 1 đến n, sau đó duyệt qua tất cả các vị trí i trong chuỗi s. Kiểm tra xem chuỗi con từ vị trí i đến i + len - 1 có đối xứng hay không và cập nhật giá trị trong ma trận isPalindrome. Tăng biến đếm lên 1 cho mỗi chuỗi con đối xứng tìm thấy. Subtask Full: - Giới hạn: s ≤ 1e5 - Hướng giải: Sử dụng phương pháp Manacher để tìm số lượng chuỗi đối xứng trong chuỗi s. Xây dựng chuỗi p bằng cách thêm ký tự đặc biệt vào giữa mỗi ký tự trong chuỗi s và ở đầu và cuối chuỗi. Sử dụng một mảng a để lưu trữ thông tin về độ dài chuỗi đối xứng tại mỗi vị trí trong chuỗi p. Duyệt qua từng vị trí trong chuỗi p và tính giá trị tương ứng của mảng a bằng phương pháp Manacher. Cuối cùng, tính tổng độ dài chuỗi đối xứng từ các giá trị trong mảng a và trả về kết quả. Đây là đoạn code tham khảo: ```cpp= #include<bits/stdc++.h> #define Nhin_lai_cuoc_doi() ios_base::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr) using namespace std; const int maxsub1 = 500; const int maxsub2 = 1000; const int full = 1e5 + 33; string pre(string s) { string p = "#"; p.reserve(2 * s.length() + 1); for (int i = 0; i < s.length(); i++) { p += s[i]; p += '#'; } return p; } bool palin(string s) { long long int l = 0, r = s.length() - 1; while (l < r) { if (s[l] != s[r]) return false; l++; r--; } return true; } long long sub1(string s) { long long res = 0, n = s.length(); for (int i = 0; i < n; i++) { for (int j = i; j < n; j++) { string substring = s.substr(i, j - i + 1); if (palin(substring)) res++; } } return res; } long long sub2(string s) { long long res = 0, n = s.length(); vector<vector<bool>> ispalin(n, vector<bool>(n, false)); for (int i = 0; i < n; i++) { ispalin[i][i] = true; res++; } for (int len = 2; len <= n; len++) { for (int i = 0; i < n - len + 1; i++) { int j = i + len - 1; if (s[i] == s[j]) { if (len == 2 || ispalin[i + 1][j - 1]) { ispalin[i][j] = true; res++; } } } } return res; } long long subfull(string s) { string p = pre(s); long long n = p.length(); vector<long long> a(n, 0); long long c = 0, rr = 0, m = 0; for (int i = 0; i < n; i++) { if (i < rr) { int j = 2 * c - i; a[i] = min(rr - i, a[j]); } long long l = i - (a[i] + 1), r = i + (a[i] + 1); while (l >= 0 && r < n && p[l] == p[r]) { a[i]++; l--; r++; } if (i + a[i] > rr) { c = i; rr = i + a[i]; } m = max(m, a[i]); } long long res = 0; for (int i = 0; i < a.size(); i++) { int len = a[i]; res += (len + 1) / 2; } return res; } int main() { Nhin_lai_cuoc_doi(); freopen("DOIXUNG.INP", "r", stdin); freopen("DOIXUNG.OUT", "w", stdout); string s; getline(cin, s); long long res; if (s.length() <= maxsub1) res = sub1(s); else if (s.length() <= maxsub2) res = sub2(s); else res = subfull(s); printf("%lld\n", res); return 0; } ```