Submission #735803

#TimeUsernameProblemLanguageResultExecution timeMemory
735803VictorBoarding Passes (BOI22_passes)C++17
100 / 100
241 ms26252 KiB
// #pragma GCC target ("avx,avx2,fma")
// #pragma GCC optimize ("Ofast,inline") // O1 - O2 - O3 - Os - Ofast
// #pragma GCC optimize ("unroll-loops")
#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (ll i = (a); i < (b); ++i)
#define per(i, a, b) for (ll i = (b) - 1; i >= (a); --i)
#define trav(a, x) for (auto &a : x)

#define all(x) x.begin(), x.end()
#define sz(x) (ll)x.size()
#define pb push_back
#define mp make_pair
#define debug(x) cout<<#x<<" = "<<x<<endl

#define umap unordered_map
#define uset unordered_set

typedef pair<int, int> ii;
typedef pair<int, ii> iii;
typedef vector<int> vi;
typedef vector<ii> vii;
typedef vector<vi> vvi;

typedef long long ll;
typedef pair<ll,ll> pll;
typedef pair<ll,pll> ppll;
typedef vector<ll> vll;
typedef vector<pll> vpll;

const ll INF = 1'000'000'007;

// 2^g state DP, what groups have boarded
// g transitions, next group to board
// to find optimal boarding side for next group we do not need to to O(N) thing
// instead we go through each group and find how many are to the left when doing binary search
// we precompute tables for each group
// something like O(2^g * g² * log n)

const ll g=15;
ll n;
string s;
double memo[1<<g];
vll groups_sum[g];
vll groups_pos[g];
vll groups_cross[g][g];

double dp(ll mask) {
    if(mask==(1<<g)-1) return 0;

    double &ans=memo[mask];
    if(ans!=-1) return ans;

    ans=1e10;
    rep(i,0,g) if(!(mask&(1<<i))) {
        
        ll group_size=sz(groups_pos[i]);
        ll lo=0,hi=group_size;

        while(hi-lo>4) {
            ll mid=(lo+hi)/2;
            //cout<<"i = "<<i<<" mid = "<<mid<<endl;

            double res[]={0,0};
            rep(k,0,2) {
                rep(j,0,g) if(mask&(1<<j)) res[k]+=double(groups_cross[i][j][mid+k]);

                ll peopleL=mid+k,peopleR=(group_size)-peopleL;
                res[k]+=double(peopleL*(peopleL-1))/4.0+double(peopleR*(peopleR-1))/4.0;
            }
            
            //if(add==100800) cout<<"peopleL = "<<peopleL<<" peopleR = "<<peopleR<<endl;
        

            if(res[0]<res[1]) hi=mid;
            else lo=mid;
        }

        //cout<<"lo = "<<lo<<" hi = "<<hi<<endl;

        rep(k,lo,hi+1) {
            double add=0;
            rep(j,0,g) if(mask&(1<<j)) add+=double(groups_cross[i][j][k]);

            ll peopleL=k,peopleR=(group_size)-peopleL;
            add+=double(peopleL*(peopleL-1))/4.0+double(peopleR*(peopleR-1))/4.0;
            
            //if(add==100800) cout<<"peopleL = "<<peopleL<<" peopleR = "<<peopleR<<endl;
            ans=min(ans,dp(mask|(1<<i))+add);
        }
    }

    //cout<<"mask = "<<mask<<" ans = "<<ans<<endl;
    return ans;
}

int main() {
    cin.tie(0)->sync_with_stdio(0);
    cin.exceptions(cin.failbit);

    rep(i,0,1<<g) memo[i]=-1;
    cin>>s;

    n=sz(s);
    trav(chr,s) chr-='A';

    rep(i,0,g) groups_sum[i].assign(n+1,0);
    rep(i,0,n) {
        ++groups_sum[(ll)s[i]][i];
        groups_pos[(ll)s[i]].pb(i);
    }

    rep(i,0,g) rep(j,1,n) groups_sum[i][j]+=groups_sum[i][j-1];
    rep(i,0,g) rep(j,0,g) {
        ll val=0;
        groups_cross[i][j].pb(0);
        trav(pos,groups_pos[i]) {
            val+=groups_sum[j][pos];
            groups_cross[i][j].pb(val);
        }
        
        val=0;
        per(k,0,sz(groups_pos[i])) {
            ll pos=groups_pos[i][k];
            val+=sz(groups_pos[j])-groups_sum[j][pos];
            groups_cross[i][j][k]+=val;
        }
    }
    
    cout<<setprecision(20)<<dp(0)<<endl;
    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...