Submission #860732

#TimeUsernameProblemLanguageResultExecution timeMemory
860732E869120Boarding Passes (BOI22_passes)C++14
100 / 100
1910 ms506676 KiB
#include <bits/stdc++.h>
using namespace std;

// Input
long long G;
long long N, A[1 << 17];
string S;

// DP
long long Cost[1 << 17][17];
long long sum1L[17][1 << 17];
long long sum1R[17][1 << 17];
long long sum2L[17][17][1 << 17];
long long sum2R[17][17][1 << 17];
long long dp[1 << 17];

long long GetLeft(int mask, int grp, int pos) {
    if (pos == 0) return 0;
    long long sum = 0;
    for (int i = 0; i < G; i++) {
        if (((mask >> i) & 1) == 0) continue;
        sum += 2LL * sum1L[i][pos - 1];
    }
    sum += 1LL * sum1L[grp][pos - 1];
    return sum;
}

long long GetRigt(int mask, int grp, int pos) {
    if (pos == 0) return 0;
    long long sum = 0;
    for (int i = 0; i < G; i++) {
        if (((mask >> i) & 1) == 0) continue;
        sum += 2LL * sum1R[i][pos + 1];
    }
    sum += 1LL * sum1R[grp][pos + 1];
    return sum;
}

long long GetLeftSum(int mask, int grp, int pos) {
    long long ret = 0;
    for (int i = 0; i < G; i++) {
        if (((mask >> i) & 1) == 0) continue;
        ret += sum2L[grp][i][pos];
    }
    ret += sum2L[grp][grp][pos];
    return ret;
}

long long GetRigtSum(int mask, int grp, int pos) {
    long long ret = 0;
    for (int i = 0; i < G; i++) {
        if (((mask >> i) & 1) == 0) continue;
        ret += sum2R[grp][i][pos];
    }
    ret += sum2R[grp][grp][pos];
    return ret;
}

long long GetCost(int mask, int grp) {
    // Step A. Binary Search
    int cl = 0, cr = N, cm;
    for (int i = 0; i < 20; i++) {
        cm = (cl + cr) / 2;
        long long v1 = GetLeft(mask, grp, cm);
        long long v2 = GetRigt(mask, grp, cm);
        if (v1 < v2) { cl = cm; }
        else { cr = cm; }
    }

    // Step B. Brute Force
    long long Return = (1LL << 60);
    for (int i = cm - 1; i <= cm + 1; i++) {
        if (i < 0 || i >= N - 1) continue;
        long long val1 = GetLeftSum(mask, grp, i);
        long long val2 = GetRigtSum(mask, grp, i + 1);
        Return = min(Return, val1 + val2);
    }
    return Return;
}

int main() {
    // Step 1. Input
    cin >> S;
    N = S.size();
    for (int i = 0; i < (int)S.size(); i++) {
        A[i] = (S[i] - 'A');
        G = max(G, A[i] + 1);
    }
    if (N <= 2) {
        cout << 0 << endl;
        return 0;
    }

    // Step 2. Precount 1
    for (int i = 0; i < N; i++) {
        sum1L[A[i]][i] += 1;
        sum1R[A[i]][i] += 1;
    }
    for (int i = 0; i < G; i++) {
        for (int j = 1; j <= N - 1; j++) sum1L[i][j] += sum1L[i][j - 1];
        for (int j = N - 2; j >= 0; j--) sum1R[i][j] += sum1R[i][j + 1];
    }

    // Step 3. Precount 2
    for (int i = 0; i < G; i++) {
        for (int j = 0; j < G; j++) {
            long long cur1 = 0;
            long long sum1 = 0;
            for (int k = 0; k < N; k++) {
                if (A[k] == i) sum1 += cur1;
                sum2L[i][j][k] = sum1;
                if (A[k] == j && i == j) cur1 += 1;
                if (A[k] == j && i != j) cur1 += 2;
            }
            long long cur2 = 0;
            long long sum2 = 0;
            for (int k = N - 1; k >= 0; k--) {
                if (A[k] == i) sum2 += cur2;
                sum2R[i][j][k] = sum2;
                if (A[k] == j && i == j) cur2 += 1;
                if (A[k] == j && i != j) cur2 += 2;
            }
        }
    }

    // Step 4. Precount 3
    for (int i = 0; i < (1 << G); i++) {
        for (int j = 0; j < G; j++) {
            if ((i >> j) & 1) continue;
            Cost[i][j] = GetCost(i, j);
        }
    }
    /*for (int i = 0; i < (1 << G); i++) {
        for (int j = 0; j < G; j++) printf("% 4lld", Cost[i][j]);
        printf("\n");
    }*/

    // Step 5. DP
    for (int i = 0; i < (1 << G); i++) dp[i] = (1LL << 60);
    dp[0] = 0;
    for (int i = 0; i < (1 << G); i++) {
        for (int j = 0; j < G; j++) {
            if ((i >> j) & 1) continue;
            dp[i + (1 << j)] = min(dp[i + (1 << j)], dp[i] + Cost[i][j]);
        }
    }

    // Step 6. Output
    printf("%.12lf\n", 0.5 * dp[(1 << G) - 1]);
    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...