제출 #561429

#제출 시각아이디문제언어결과실행 시간메모리
561429Ooops_sorry회문 (APIO14_palindrome)C++14
0 / 100
1083 ms43872 KiB
#include<bits/stdc++.h> using namespace std; #define pb push_back #define ld long double #define ll long long mt19937 rnd(51); const int INF = 1e9, MOD1 = 1e9 + 7, p1 = 31, MOD2 = 1e9 + 33, p2 = 37; bool is_palindrome(string s) { return s == (string){s.rbegin(), s.rend()}; } int solve1(string s) { int n = s.size(), ans = -INF; map<string, int> cnt; for (int i = 0; i < n; i++) { for (int j = 1; j + i <= n; j++) { cnt[s.substr(i, j)]++; } } for (int i = 0; i < n; i++) { for (int j = n - i; j >= 1; j--) { if (is_palindrome(s.substr(i, j))) { ans = max(ans, cnt[s.substr(i, j)] * j); } } } return ans; } struct Hash { ll MOD, p; vector<ll> po, h; Hash(string s, ll MOD_, ll p_) { MOD = MOD_, p = p_; int n = s.size(); po.resize(n + 1); h.resize(n + 1); po[0] = 1; for (int i = 1; i <= n; i++) { po[i] = (po[i - 1] * p) % MOD; } for (int i = 0; i < n; i++) { h[i + 1] = (h[i] * p + s[i] - 'a' + 1) % MOD; } } int get(int l, int r) { r++; return (((h[r] - h[l] * po[r - l]) % MOD) + MOD) % MOD; } }; struct SegTree { vector<int> t; SegTree(int n) { t.resize(4 * n, -1); } void update(int v, int tl, int tr, int l, int r, int val) { if (l > r) return; if (tl == l && tr == r) { t[v] = max(t[v], val); return; } int tm = (tl + tr) / 2; update(2 * v, tl, tm, l, min(r, tm), val), update(2 * v + 1, tm + 1, tr, max(l, tm + 1), r, val); } int get(int v, int l, int r, int pos) { if (l == r) { return t[v]; } int m = (l + r) / 2; if (pos <= m) { return max(t[v], get(2 * v, l, m, pos)); } else { return max(t[v], get(2 * v + 1, m + 1, r, pos)); } } }; struct SegTreeMax { vector<int> t; int n; SegTreeMax(int n_) { n = n_; t.resize(2 * n, -INF); } void upd(int i, int val) { i += n; t[i] = val; for (; i > 1; i /= 2) { t[i / 2] = min(t[i], t[i ^ 1]); } } int get(int l, int r) { int ans = INF; l += n, r += n + 1; while (l < r) { if (l & 1) { ans = min(ans, t[l++]); } if (r & 1) { ans = min(ans, t[--r]); } l /= 2, r /= 2; } return ans; } }; vector<int> suffix_array(string s) { s += '#'; int n = s.size(); vector<int> c(n), ord(n); iota(ord.begin(), ord.end(), 0); sort(ord.begin(), ord.end(), [&](int i, int j){return s[i] < s[j];}); int now = 0; for (int i = 0; i < n; i++) { if (i - 1 >= 0 && s[ord[i]] != s[ord[i - 1]]) { now++; } c[ord[i]] = now; } for (int j = 0; j < 20; j++) { vector<int> c_(n); vector<array<int, 3>> u; for (int i = 0; i < n; i++) { u.pb({c[i], c[(i + (1 << j)) % n], i}); } sort(u.begin(), u.end()); int now = 0; for (int i = 0; i < n; i++) { if (i - 1 >= 0 && (u[i - 1][0] != u[i][0] || u[i - 1][1] != u[i][1])) { now++; } c_[u[i][2]] = now; } c = c_; } vector<int> ans(n - 1); for (int i = 0; i + 1 < n; i++) { ans[c[i] - 1] = i; } return ans; } int solve2(string s) { int n = s.size(), ans = -INF; Hash h1(s, MOD1, p1), h1rev((string){s.rbegin(), s.rend()}, MOD1, p1), h2(s, MOD2, p2), h2rev(s, MOD2, p2); SegTree odd(n), even(n); for (int i = 0; i < n; i++) { int l = 0, r = n; while (r - l > 1) { int mid = (r + l) / 2; if (i - mid >= 0 && i + mid < n && h1.get(i - mid, i + mid) == h1rev.get(n - i - mid - 1, n - i + mid - 1) && h2.get(i - mid, i + mid) == h2rev.get(n - i - mid - 1, n - i + mid - 1)) { l = mid; } else { r = mid; } } odd.update(1, 0, n - 1, i - l, i, i); if (i + 1 < n && s[i] == s[i + 1]) { int l = 0, r = n; while (r - l > 1) { int mid = (r + l) / 2; if (i - mid >= 0 && i + mid + 1 < n && h1.get(i - mid, i + mid + 1) == h1rev.get(n - i - mid - 2, n - i + mid - 1) && h2.get(i - mid, i + mid + 1) == h2rev.get(n - i - mid - 2, n - i + mid - 1)) { l = mid; } else { r = mid; } } even.update(1, 0, n - 1, i - l, i, i); } } vector<int> pos(n, -1); for (int i = 0; i < n; i++) { int j = odd.get(1, 0, n - 1, i), k = even.get(1, 0, n - 1, i); if (j != -1) { pos[i] = max(pos[i], i + 2 * (j - i)); } if (k != -1) { pos[i] = max(pos[i], i + 1 + 2 * (k - i)); } } vector<int> arr = suffix_array(s), p; SegTreeMax tr(n - 1); for (int i = 0; i + 1 < n; i++) { if (s[arr[i]] != s[arr[i + 1]]) { tr.upd(i, 0); p.pb(0); } else { int l = 0, r = n; while (r - l > 1) { int mid = (r + l) / 2; if (max(arr[i], arr[i + 1]) + mid <= n && h1.get(arr[i], arr[i] + mid - 1) == h1.get(arr[i + 1], arr[i + 1] + mid - 1) && h2.get(arr[i], arr[i] + mid - 1) == h2.get(arr[i + 1], arr[i + 1] + mid - 1)) { l = mid; } else { r = mid; } } tr.upd(i, l); p.pb(l); } } for (int i = 0; i < n; i++) { if (pos[arr[i]] == -1) continue; int len = pos[arr[i]] - arr[i] + 1, cnt = 1; if (i + 1 < n && p[i] >= len) { int l = i, r = n - 1; while (r - l > 1) { int mid = (r + l) / 2; if (tr.get(i, mid) >= len) { l = mid; } else { r = mid; } } cnt += l - i + 1; } if (i - 1 >= 0 && p[i - 1] >= len) { int l = -1, r = i - 1; while (r - l > 1) { int mid = (r + l) / 2; if (tr.get(mid, i - 1) >= len) { r = mid; } else { l = mid; } } cnt += i - r; } ans = max(ans, cnt * len); } return ans; } signed main() { #ifdef LOCAL freopen("input.txt", "r", stdin); #endif // LCOAL ios_base::sync_with_stdio(0); cin.tie(0); while (0) { int n = rnd() % 10 + 1; string s = ""; for (int i = 0; i < n; i++) { s += rnd() % 5 + 'a'; } auto res1 = solve1(s), res2 = solve2(s); if (res1 != res2) { cout << s << endl << res1 << ' ' << res2 << endl; return 0; } cout << "ok" << endl; } string s; cin >> s; cout << solve2(s) << endl; return 0; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...