Submission #855936

#TimeUsernameProblemLanguageResultExecution timeMemory
855936SortingOvertaking (IOI23_overtaking)C++17
100 / 100
2193 ms162288 KiB
#include "overtaking.h"
#include <algorithm>
#include <map>
#include <numeric>

using namespace std;
typedef long long ll;

const int N = 1000 + 3;

ll dp[N][N];
int n, m;
ll t[N], w[N], s[N], l, x;

map<ll, pair<vector<int>, int>> groups[N];
map<ll, pair<vector<int>, int>>::iterator iters[N][N];
ll time_at_sorting[N][N];

void reorder_buses(){
    int new_n = n;
    for(int i = 0; i < new_n; ++i){
        if(w[i] <= x){
            --new_n;
            swap(w[i], w[new_n]);
            swap(t[i], t[new_n]);
            --i;
        }
    }
    n = new_n;

    vector<int> perm(n);
    iota(perm.begin(), perm.end(), 0);

    sort(perm.begin(), perm.end(), [&](int l, int r){
        if(w[l] != w[r])
            return w[l] < w[r];
        return t[l] < t[r];
    });

    static ll tmp[N];
    copy(t, t + n, tmp);
    for(int i = 0; i < n; ++i){
        t[i] = tmp[perm[i]];
    }
    copy(w, w + n, tmp);
    for(int i = 0; i < n; ++i){
        w[i] = tmp[perm[i]];
    }
}

void init_groups(){
    for(int i = 0; i < n; ++i){
        time_at_sorting[0][i] = t[i];
        groups[0][t[i]].first.push_back(i);
    }

    {
        int curr_cnt = 0;
        for(auto iter = groups[0].begin(); iter != groups[0].end(); ++iter){
            auto &[time, p] = *iter;
            for(int i = curr_cnt + 1; i <= curr_cnt + p.first.size(); ++i){
                iters[0][i] = iter;
            }
            curr_cnt += p.first.size();
            p.second = curr_cnt;
        }
    }

    for(int station = 1; station < m; ++station){
        vector<int> order;
        for(auto &[time, p]: groups[station - 1]){
            auto &v = p.first;
            for(int x: v){
                order.push_back(x);
            }
        }

        for(int i = 0; i < n; ++i){
            time_at_sorting[station][i] = time_at_sorting[station - 1][i] + (s[station] - s[station - 1]) * w[i];
        }

        ll max_so_far = 0;
        for(int x: order){
            max_so_far = max(max_so_far, time_at_sorting[station][x]);
            time_at_sorting[station][x] = max_so_far;
            groups[station][max_so_far].first.push_back(x);
        }

        int curr_cnt = 0;
        for(auto iter = groups[station].begin(); iter != groups[station].end(); ++iter){
            auto &[time, p] = *iter;

            auto &buses = p.first;
            auto &cnt = p.second;
            sort(buses.begin(), buses.end());

            for(int i = curr_cnt + 1; i <= curr_cnt + buses.size(); ++i){
                iters[station][i] = iter;
            }

            curr_cnt += buses.size();
            cnt = curr_cnt;
        }
    }
}

void init_buses(){
    reorder_buses();
    init_groups();
}

ll calc_time(int station, ll time){
    if(station == m - 1){
        return time;
    }

    int curr_cnt = 0;
    {
        auto curr_iter = groups[station].lower_bound(time);
        if(curr_iter == groups[station].begin()){
            curr_cnt = 0;
        }
        else{
            --curr_iter;
            curr_cnt = curr_iter->second.second;
        }
    }
    
    if(!curr_cnt){
        return (s[m - 1] - s[station]) * x + time;
    }

    int l = station + 1, r = m;
    while(l != r){
        int mid = (l + r) >> 1;
        
        ll time_at_mid = (s[mid] - s[station]) * x + time;

        auto iter = iters[mid][curr_cnt];
        int cnt = iter->second.second;
        ll time_at_iter = iter->first;

        if(time_at_iter >= time_at_mid){
            r = mid;
        }
        else{
            l = mid + 1;
        }
    }

    int next_station = l;
    if(next_station == m){
        return (s[m - 1] - s[station]) * x + time;
    }

    int prev_station = next_station - 1;
    ll time_at_prev_station = (s[prev_station] - s[station]) * x + time;

    auto iter = groups[prev_station].lower_bound(time_at_prev_station);
    if(iter == groups[prev_station].begin()){
        return (s[m - 1] - s[station]) * x + time;
    }

    --iter;
    int bus = iter->second.first.back();
    return dp[next_station][bus];
}

void calc_dp(){
    for(int station = m - 1; station >= 0; --station){
        if(station == m - 1){
            for(int i = 0; i < n; ++i){
                dp[station][i] = time_at_sorting[station][i];
            }
            continue;
        }

        for(int i = 0; i < n; ++i){
            dp[station][i] = calc_time(station, time_at_sorting[station][i]);
        }
    }
}

void init(int L, int N, vector<long long> T, vector<int> W, int X, int M, vector<int> S)
{
    l = L, n = N, x = X, m = M;
    copy(T.begin(), T.end(), t);
    copy(W.begin(), W.end(), w);
    copy(S.begin(), S.end(), s);

    init_buses();
    calc_dp();
}

ll arrival_time(ll Y)
{
    return calc_time(0, Y);
}

Compilation message (stderr)

overtaking.cpp: In function 'void init_groups()':
overtaking.cpp:61:41: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   61 |             for(int i = curr_cnt + 1; i <= curr_cnt + p.first.size(); ++i){
      |                                       ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
overtaking.cpp:97:41: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   97 |             for(int i = curr_cnt + 1; i <= curr_cnt + buses.size(); ++i){
      |                                       ~~^~~~~~~~~~~~~~~~~~~~~~~~~~
overtaking.cpp: In function 'll calc_time(int, ll)':
overtaking.cpp:140:13: warning: unused variable 'cnt' [-Wunused-variable]
  140 |         int cnt = iter->second.second;
      |             ^~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...