There is a string $s$ of lowercase English letters. A cursor is positioned on one of the characters. The cursor can be moved with the following operation: choose a letter $c$ and a direction (left or right). The cursor is then moved to the closest occurence of $c$ in the chosen direction. If there is no letter $c$ in that direction, the cursor stays in place. For example, if $s = \mathtt{abaab}$ with the cursor on the second character ($\mathtt{a[b]aab}$), then:
- moving to the closest letter $\mathtt{a}$ to the left places the cursor on the first character ($\mathtt{[a]baab}$);
- moving to the closest letter $\mathtt{a}$ to the right places the cursor the third character ($\mathtt{ab[a]ab}$);
- moving to the closest letter $\mathtt{b}$ to the right places the cursor on the fifth character ($\mathtt{abaa[b]}$);
- any other operation leaves the cursor in place.
Let $\mathrm{dist}(i, j)$ be the smallest number of operations needed to move the cursor from the $i$-th character to the $j$-th character. Compute $\displaystyle \sum_{i = 1}^n \sum_{j = 1}^n \mathrm{dist}(i, j)$.Input
The only line contains a non-empty string $s$ of at most $10^5$ lowercase English letters.Output
Print a single integer $\displaystyle \sum_{i = 1}^n \sum_{j = 1}^n \mathrm{dist}(i, j)$.
Examples input
abcde
output
20
input
abacaba
output
58
Note
In the first sample case, $\mathrm{dist}(i, j) = 0$ for any pair $i = j$, and $1$ for all other pairs.
Solution:
#undef _GLIBCXX_DEBUG
#include <bits/stdc++.h>
using namespace std;
template <typename A, typename B>
string to_string(pair<A, B> p);
template <typename A, typename B, typename C>
string to_string(tuple<A, B, C> p);
template <typename A, typename B, typename C, typename D>
string to_string(tuple<A, B, C, D> p);
string to_string(const string& s) {
return '"' + s + '"';
}
string to_string(const char* s) {
return to_string((string) s);
}
string to_string(bool b) {
return (b ? "true" : "false");
}
string to_string(vector<bool> v) {
bool first = true;
string res = "{";
for (int i = 0; i < static_cast<int>(v.size()); i++) {
if (!first) {
res += ", ";
}
first = false;
res += to_string(v[i]);
}
res += "}";
return res;
}
template <size_t N>
string to_string(bitset<N> v) {
string res = "";
for (size_t i = 0; i < N; i++) {
res += static_cast<char>('0' + v[i]);
}
return res;
}
template <typename A>
string to_string(A v) {
bool first = true;
string res = "{";
for (const auto &x : v) {
if (!first) {
res += ", ";
}
first = false;
res += to_string(x);
}
res += "}";
return res;
}
template <typename A, typename B>
string to_string(pair<A, B> p) {
return "(" + to_string(p.first) + ", " + to_string(p.second) + ")";
}
template <typename A, typename B, typename C>
string to_string(tuple<A, B, C> p) {
return "(" + to_string(get<0>(p)) + ", " + to_string(get<1>(p)) + ", " + to_string(get<2>(p)) + ")";
}
template <typename A, typename B, typename C, typename D>
string to_string(tuple<A, B, C, D> p) {
return "(" + to_string(get<0>(p)) + ", " + to_string(get<1>(p)) + ", " + to_string(get<2>(p)) + ", " + to_string(get<3>(p)) + ")";
}
void debug_out() { cerr << endl; }
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
cerr << " " << to_string(H);
debug_out(T...);
}
#ifdef LOCAL
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
string foo;
cin >> foo;
vector<int> s(foo.size());
int n = (int) s.size();
for (int i = 0; i < n; i++) {
s[i] = (int) (foo[i] - 'a');
}
const int ALPHA = 26;
vector<vector<int>> prev(n, vector<int>(ALPHA));
for (int c = 0; c < ALPHA; c++) {
prev[0] = -1;
}
for (int i = 1; i < n; i++) {
prev[i] = prev[i - 1];
prev[i][s[i - 1]] = i - 1;
}
vector<vector<int>> next(n, vector<int>(ALPHA));
for (int c = 0; c < ALPHA; c++) {
next[n - 1] = n;
}
for (int i = n - 2; i >= 0; i--) {
next[i] = next[i + 1];
next[i][s[i + 1]] = i + 1;
}
vector<vector<int>> prev_order(n, vector<int>(ALPHA));
for (int i = 0; i < n; i++) {
iota(prev_order[i].begin(), prev_order[i].end(), 0);
sort(prev_order[i].begin(), prev_order[i].end(), [&](int x, int y) {
return prev[i][x] > prev[i][y];
});
}
vector<vector<int>> next_order(n, vector<int>(ALPHA));
for (int i = 0; i < n; i++) {
iota(next_order[i].begin(), next_order[i].end(), 0);
sort(next_order[i].begin(), next_order[i].end(), [&](int x, int y) {
return next[i][x] < next[i][y];
});
}
auto Submask = [&](int A, int B) {
return ((A & B) == A);
};
vector<long long> res(n, n - 1);
vector<int> subset(n);
vector<int> L(n), R(n);
for (int i = 0; i < n; i++) {
subset[i] = (1 << s[i]);
L[i] = i;
R[i] = i;
}
int real_alpha = 0;
for (int i = 0; i < n; i++) {
real_alpha |= subset[i];
}
real_alpha = __builtin_popcount(real_alpha);
const int LOG = 19;
vector<vector<int>> jumpL(n, vector<int>(LOG, 0));
vector<vector<int>> jumpR(n, vector<int>(LOG, n - 1));
vector<int> cntJumpL(n);
vector<int> cntJumpR(n);
vector<vector<long long>> sumJumpL(n, vector<long long>(LOG, 0));
vector<vector<long long>> sumJumpR(n, vector<long long>(LOG, 0));
vector<int> prev_subset(n, 0);
vector<int> next_subset(n, 0);
for (int pc = 1; pc <= real_alpha; pc++) {
for (int i = 0; i < n; i++) {
if (prev[i][prev_order[i][pc - 1]] != -1) {
prev_subset[i] |= (1 << prev_order[i][pc - 1]);
}
if (next[i][next_order[i][pc - 1]] != n) {
next_subset[i] |= (1 << next_order[i][pc - 1]);
}
}
cntJumpL[0] = n;
for (int i = 1; i < n; i++) {
jumpL[i][0] = max(0, prev[i][prev_order[i][pc - 1]]);
if (jumpL[i][0] == 0) {
cntJumpL[i] = n;
} else {
if (!Submask(prev_subset[jumpL[i][0]], prev_subset[i])) {
cntJumpL[i] = 1;
} else {
cntJumpL[i] = cntJumpL[jumpL[i][0]] + 1;
}
}
sumJumpL[i][0] = jumpL[i][0];
}
cntJumpR[n - 1] = n;
for (int i = n - 2; i >= 0; i--) {
jumpR[i][0] = min(n - 1, next[i][next_order[i][pc - 1]]);
if (jumpR[i][0] == n - 1) {
cntJumpR[i] = n;
} else {
if (!Submask(next_subset[jumpR[i][0]], next_subset[i])) {
cntJumpR[i] = 1;
} else {
cntJumpR[i] = cntJumpR[jumpR[i][0]] + 1;
}
}
sumJumpR[i][0] = n - 1 - jumpR[i][0];
}
// debug(cntJumpR);
// debug(next_subset);
vector<int> jumps(n);
int max_jumps = 0;
for (int i = 0; i < n; i++) {
if (__builtin_popcount(subset[i]) != pc) {
continue;
}
int cntL = 0;
int cntR = 0;
if (Submask(prev_subset[L[i]], subset[i]) || L[i] == 0) {
cntL = max(0, cntJumpL[L[i]]);
}
if (Submask(next_subset[R[i]], subset[i]) || R[i] == n - 1) {
cntR = max(0, cntJumpR[R[i]]);
}
jumps[i] = (pc == real_alpha ? max(cntL, cntR) : min(cntL, cntR));
max_jumps = max(max_jumps, jumps[i]);
}
int CUR_LOG = 0;
while ((1 << CUR_LOG) <= max_jumps) {
CUR_LOG += 1;
}
for (int j = 1; j < CUR_LOG; j++) {
for (int i = 0; i < n; i++) {
jumpL[i][j] = jumpL[jumpL[i][j - 1]][j - 1];
sumJumpL[i][j] = sumJumpL[i][j - 1] + sumJumpL[jumpL[i][j - 1]][j - 1];
jumpR[i][j] = jumpR[jumpR[i][j - 1]][j - 1];
sumJumpR[i][j] = sumJumpR[i][j - 1] + sumJumpR[jumpR[i][j - 1]][j - 1];
}
}
for (int i = 0; i < n; i++) {
if (__builtin_popcount(subset[i]) != pc) {
continue;
}
// debug(pc, subset[i], i, L[i], R[i], cntL, cntR, jumps);
for (int j = 0; j < CUR_LOG; j++) {
if (jumps[i] & (1 << j)) {
res[i] += sumJumpL[L[i]][j];
L[i] = jumpL[L[i]][j];
res[i] += sumJumpR[R[i]][j];
R[i] = jumpR[R[i]][j];
}
}
int newL = L[i];
int newR = R[i];
for (int c = 0; c < ALPHA; c++) {
if (subset[i] & (1 << c)) {
newL = min(newL, prev[L[i]]);
newR = max(newR, next[R[i]]);
}
}
newL = max(newL, 0);
newR = min(newR, n - 1);
L[i] = newL;
R[i] = newR;
res[i] += newL + (n - 1 - newR);
int new_subset = 0;
for (int c = 0; c < ALPHA; c++) {
if (s[L[i]] == c || next[L[i]] <= R[i]) {
new_subset |= (1 << c);
}
}
// debug(pc, i, L[i], R[i], subset[i], new_subset);
assert(pc == real_alpha || __builtin_popcount(new_subset) > pc);
subset[i] = new_subset;
}
}
// debug(subset, L, R, res);
long long ans = 0;
for (int i = 0; i < n; i++) {
ans += res[i];
}
cout << ans << '\n';
cerr << "time = " << clock() << " ms" << '\n';
return 0;
}