1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
| #include <algorithm> #include <cassert> #include <iostream> #include <string> #include <utility> #include <vector>
using pii = std::pair<int, int>;
class SegTree { std::vector<int> tree; std::vector<int> maxpos; int n; void add(int p, int l, int r, int pos, int val) { if (l == r) { tree[p] += val; maxpos[p] = pos; return; } int mid = l + ((r - l) >> 1); if (pos <= mid) add(p * 2, l, mid, pos, val); else add(p * 2 + 1, mid + 1, r, pos, val); tree[p] = tree[p * 2] + tree[p * 2 + 1]; maxpos[p] = std::max(maxpos[p * 2], maxpos[p * 2 + 1]); } int sum(int p, int l, int r, int ql, int qr) const { if (ql > r || qr < l) return 0; if (ql <= l && r <= qr) return tree[p]; int mid = l + ((r - l) >> 1); return sum(p * 2, l, mid, ql, qr) + sum(p * 2 + 1, mid + 1, r, ql, qr); } int mr(int p, int l, int r, int ql, int qr) { if (ql > r || qr < l) return -1; if (ql <= l && r <= qr) return maxpos[p]; int mid = l + ((r - l) >> 1); return std::max(mr(p * 2, l, mid, ql, qr), mr(p * 2 + 1, mid + 1, r, ql, qr)); }
public: SegTree(int n_) : tree(5 * n_, 0), n{n_}, maxpos(5 * n_, -1) {} void add(int pos, int val) { add(1, 0, n - 1, pos, val); } int sum(int ql, int qr) const { return ql <= qr ? sum(1, 0, n - 1, ql, qr) : 0; } int maxr(int pos, int l, int r) { if (l >= r) return pos; else return mr(1, 0, n - 1, l, r); } int operator[](int pos) const { assert(pos >= 0 && pos < n); return sum(pos, pos); } };
int main() { std::string s; std::cin >> s;
std::string aug = "#"; for (char c : s) { aug += c; aug += '#'; }
std::vector<int> maxlen; std::vector<std::vector<int>> lbound(aug.size() + 1); int l = 0, r = -1;
for (int i = 0, lr = aug.size(); i < lr; i++) { int tmp = (i > r ? 0 : std::min(maxlen[l + r - i], r - i)); while (i - tmp >= 0 && i + tmp < lr && aug[i - tmp] == aug[i + tmp]) ++tmp; tmp--; maxlen.push_back(tmp); if (i + tmp > r) { l = i - tmp; r = i + tmp; } if (i % 2 == 0) lbound.at(i - tmp).push_back(i); }
long long ans = 0; SegTree st(aug.size() + 1); std::vector<pii> str;
for (int i = 0; i < aug.size(); i++) { for (auto e : lbound.at(i)) { assert(e % 2 == 0); st.add(e, 1); }
if (i % 2 == 0) { int v = st.sum(i + 1, i + maxlen[i] / 2); ans += v; int len = st.maxr(i, i + 1, i + maxlen[i] / 2); if (len > i) str.push_back({(i + 1 - (len - i) * 2) / 2, +(i - 1 + (len - i) * 2) / 2}); } else str.push_back({i / 2, i / 2}); }
std::sort(str.begin(), str.end(), [](const pii &a, const pii &b) { return a.first < b.first || (a.first == b.first && a.second > b.second); }); int cnt = 0, R = -1; for (int i = 0; i < str.size();) { int tr = -1, j = i; while (j < str.size() && str.at(j).first <= R) { tr = std::max(tr, str[j].second); j++; } tr = std::max(tr, str[j].second); if (j < str.size()) cnt++, R = tr; i = j + 1; } std::cout << ans + s.size() << ' ' << cnt << '\n'; }
|