#include <bits/stdc++.h>
#define CHECK_BIT(var, pos) (((var) & (1 << (pos))) != 0)
#define pb push_back
using namespace std;
typedef pair<int, int> pi;
typedef long long ll;
const ll INF = 1e18;
string s;
int N, G;
vector<vector<int>> spots;
vector<int> group;
vector<vector<ll>> optimal;
vector<vector<vector<ll>>> pref, suff;
vector<ll> self;
// We take to the left everything up to but NOT including spots[g][cut]
ll cost(int m, int g, int cut) {
    ll ans = 0;
    for (int b = 0; b < G; b++) {
        if (CHECK_BIT(m, b)) {
            ans += 2 * suff[g][cut][b];
            ans += 2 * pref[g][cut][b];
        }
    }
    ans += self[cut] + self[spots[g].size() - cut];
    return ans;
}
void calculate(int g, int mask) {
    // Goal is to find first step that becomes increasing
    int l = -1;
    int r = spots[g].size();
    while (l + 1 < r) {
        int mid = (l + r) / 2;
        if (cost(mask, g, mid) > cost(mask, g, mid + 1)) {
            l = mid;
        }
        else {
            r = mid;
        }
    }
    optimal[g][mask] = cost(mask, g, r);
}
int main(void) {
    cin >> s;
    N = s.size();
    group.resize(N);
    vector<int> allgroups;
    for (int i = 0; i < N; i++) {
        group[i] = s[i] - 'A';
        allgroups.pb(group[i]);
    }
    sort(allgroups.begin(), allgroups.end());
    allgroups.resize(unique(allgroups.begin(), allgroups.end()) - allgroups.begin());
    G = allgroups.size();
    for (int i = 0; i < N; i++) {
        group[i] = lower_bound(allgroups.begin(), allgroups.end(), group[i]) - allgroups.begin();
    }
    spots.resize(G);
    self.resize(N + 1);
    optimal.assign(G, vector<ll>(1 << G, 0));
    for (int i = 0; i < N; i++) {
        spots[group[i]].pb(i);
    }
    self[1] = 0;
    for (int i = 2; i <= N; i++) {
        self[i] = self[i - 1] + i - 1;
    }
    pref.resize(G);
    suff.resize(G);
    for (int g = 0; g < G; g++) {
        // Start with nothing left, everything right
        pref[g].resize(spots[g].size() + 1, vector<ll>(G, 0));
        suff[g].resize(spots[g].size() + 1, vector<ll>(G, 0));
        vector<ll> cntsuff(G);
        vector<ll> cntpref(G);
        // Calculate suffix first
        for (int p = N - 1; p >= 0; p--) {
            cntsuff[group[p]]++;
            if (group[p] == g) {
                for (int b = 0; b < G; b++) {
                    suff[g][0][b] += cntsuff[b];
                }
            }
        }
        // Now update position by position
        int p = 0;
        
        for (int i = 0; i < spots[g].size(); i++) {
            while (p < spots[g][i]) {
                cntpref[group[p]]++;
                cntsuff[group[p]]--;
                p++;
            }
            for (int b = 0; b < G; b++) {
                pref[g][i + 1][b] = pref[g][i][b] + cntpref[b];
                suff[g][i + 1][b] = suff[g][i][b] - cntsuff[b];
            }
        }
        // Now calculate optimality
        for (int mask = 0; mask < (1 << G); mask++) {
            if (!CHECK_BIT(mask, g)) {
                calculate(g, mask);
            }
        }
    }
    vector<ll> dp(1 << G, INF);
    dp[0] = 0;
    for (int s = 1; s < (1 << G); s++) {
        for (int b = 0; b < G; b++) {
            if (CHECK_BIT(s, b)) {
                int prv = s - (1 << b);
                dp[s] = min(dp[s], dp[prv] + optimal[b][prv]);
            }
        }
    }
    printf("%lf\n", (double)dp[(1 << G) - 1] / 2);
    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... |