This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
#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;
map<int, int> cnt;
Hash h(s, MOD1, p1), hrev((string){s.rbegin(), s.rend()}, MOD1, p1);
for (int i = 0; i < n; i++) {
for (int j = 1; j + i <= n; j++) {
cnt[h.get(i, i + j - 1)]++;
}
}
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 && h.get(i - mid, i + mid) == hrev.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 && h.get(i - mid, i + mid + 1) == hrev.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 && h.get(arr[i], arr[i] + mid - 1) == h.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 time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |