Submission #763586

#TimeUsernameProblemLanguageResultExecution timeMemory
763586boris_mihovWiring (IOI17_wiring)C++17
100 / 100
135 ms17944 KiB
#include "wiring.h"
#include <algorithm>
#include <iostream>
#include <numeric>
#include <cassert>
#include <vector>
#include <set>
 
typedef long long llong;
const int MAXN = 200000 + 10;
const llong LLINF = 1e18;
const int INF = 1e9;

int n, m;
struct SegmentTree
{
    llong tree[4*MAXN];
    void update(int l, int r, int node, int queryPos, llong queryValue)
    {
        if (l == r)
        {
            tree[node] = queryValue;
            return;
        }

        int mid = (l + r) / 2;
        if (queryPos <= mid) update(l, mid, 2*node, queryPos, queryValue);
        else update(mid + 1, r, 2*node + 1, queryPos, queryValue);
        tree[node] = std::min(tree[2*node], tree[2*node + 1]);
    }

    llong query(int l, int r, int node, int queryL, int queryR)
    {
        if (queryL <= l && r <= queryR)
        {
            return tree[node];
        }

        llong res = LLINF;
        int mid = (l + r) / 2;
        if (queryL <= mid) res = std::min(res, query(l, mid, 2*node, queryL, queryR));
        if (mid + 1 <= queryR) res = std::min(res, query(mid + 1, r, 2*node + 1, queryL, queryR));
        return res;
    }

    void update(int pos, llong val)
    {
        update(1, n + m + 1, 1, pos, val);
    }

    llong query(int l, int r)
    {
        return query(1, n + m + 1, 1, l, r);
    }
};

llong dp[MAXN];
llong suff[MAXN];
llong prefix[MAXN];
SegmentTree leftTree; // left is longer
SegmentTree rightTree; // right is longer
std::pair <int,bool> a[MAXN];
int inBucket[MAXN];
int right[MAXN];
int left[MAXN];

llong min_total_length(std::vector <int> R, std::vector <int> B) 
{
    n = R.size();
    m = B.size();

    for (int i = 1 ; i <= n ; ++i)
    {
        a[i] = {R[i - 1], false};
    }

    for (int i = 1 ; i <= m ; ++i)
    {
        a[n + i] = {B[i - 1], true};
    }

    std::sort(a + 1, a + 1 + n + m);
    a[0].second = a[1].second ^ 1;
    int cnt = 0;

    for (int i = 1 ; i <= n + m ; ++i)
    {
        if (a[i].second == a[i - 1].second)
        {
            right[cnt] = i;
        } else
        {
            cnt++;
            left[cnt] = right[cnt] = i;
        }

        inBucket[i] = cnt;
    }

    for (int i = 1 ; i <= n + m ; ++i)
    {
        prefix[i] = prefix[i - 1] + a[i].first;
    } 

    leftTree.update(1, -a[left[2]].first);
    rightTree.update(1, -a[right[1]].first);
    for (int i = 1 ; i <= n + m ; ++i)
    {
        if ((i > 1 && inBucket[i] != inBucket[i - 1]) || (i > 2 && inBucket[i - 2] != inBucket[i - 1]))
        {
            for (int j = i - 2 ; j >= left[inBucket[i - 2]] ; --j)
            {
                dp[j] = std::min(dp[j], dp[j + 1]);
            }

            for (int j = left[inBucket[i - 2]] ; j < i ; ++j)
            {
                leftTree.update(j + 1, prefix[j] + dp[j] - 1LL * (j + 1) * a[left[inBucket[j + 1] + 1]].first);
                rightTree.update(j + 1, prefix[j] + dp[j] - 1LL * (j + 1) * a[right[inBucket[j + 1]]].first);
            }

            dp[i] = 0;
        }

        if (inBucket[i] == 1)
        {
            dp[i] = LLINF;
        } else
        {
            int prevL = left[inBucket[i] - 1];
            int prevR = right[inBucket[i] - 1];

            if (i - prevR >= prevR - prevL + 1)
            {
                dp[i] = rightTree.query(prevL, prevR) + 1LL * (2 * prevR + 1 - i) * a[prevR].first;
            } else
            {
                int equalPos = prevR - (i - prevR - 1);
                dp[i] = rightTree.query(equalPos, prevR) + 1LL * (2 * prevR + 1 - i) * a[prevR].first;
                dp[i] = std::min(dp[i], leftTree.query(prevL, equalPos - 1) + 1LL * (2 * prevR + 1 - i) * a[prevR + 1].first);
            }
            
            dp[i] += prefix[i] - 2 * prefix[prevR]; 
        }
    }

    return dp[n + m];
}
#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...