Submission #1077748

#TimeUsernameProblemLanguageResultExecution timeMemory
1077748EliasWiring (IOI17_wiring)C++17
100 / 100
183 ms23908 KiB
// #pragma GCC optimize("O3")
// #pragma GCC optimize("unroll-loops")

#include <bits/stdc++.h>

using namespace std;

#define ll long long

#ifdef _DEBUG
long long min_total_length(std::vector<int> r, std::vector<int> b);
#else
#include "wiring.h"
#endif

ll inf = LLONG_MAX / 10;

template <typename T>
struct LzySegtree
{
	vector<T> b;
	vector<T> updates;
	int n;

	void prop(int l, int r, int i)
	{
		b[i] += updates[i];
		if (l + 1 != r)
		{
			updates[i * 2 + 1] += updates[i];
			updates[i * 2 + 2] += updates[i];
		}
		updates[i] = 0;
	}

	T segUpdate(int l, int r, int i, int ul, int ur, T delta)
	{
		prop(l, r, i);
		if (ul >= r || ur <= l)
			return b[i];
		if (ul <= l && ur >= r)
		{
			updates[i] += delta;
			prop(l, r, i);
			return b[i];
		}
		int m = (l + r) / 2;
		return b[i] = min(segUpdate(l, m, i * 2 + 1, ul, ur, delta), segUpdate(m, r, i * 2 + 2, ul, ur, delta));
	}

	T segGet(int l, int r, int i, int ql, int qr)
	{
		prop(l, r, i);
		if (ql >= r || qr <= l)
			return T(inf);
		if (ql <= l && qr >= r)
			return b[i];
		int m = (l + r) / 2;
		return min(segGet(l, m, i * 2 + 1, ql, qr), segGet(m, r, i * 2 + 2, ql, qr));
	}

	T segBuild(int l, int r, int i, vector<T> &a)
	{
		if (l + 1 == r)
			return b[i] = a[l];
		int m = (l + r) / 2;
		return b[i] = min(segBuild(l, m, i * 2 + 1, a), segBuild(m, r, i * 2 + 2, a));
	}

	LzySegtree(vector<T> a)
	{
		n = a.size();
		b.resize(4 * n, T(inf));
		updates.resize(4 * n, 0);
		segBuild(0, n, 0, a);
	}
};

vector<pair<int, int>> all;
map<int, ll> mem;

/// @brief  Assume r is sorted backwards and b forwards
/// @param r
/// @param b
ll match(vector<int> r, vector<int> b)
{
	int n = r.size();
	int m = b.size();

	ll total = 0;

	for (int i = 0; i < max(n, m); i++)
	{
		ll x = r.back();
		ll y = b.back();

		total += abs(x - y);

		if (r.size() > 1)
			r.pop_back();
		if (b.size() > 1)
			b.pop_back();
	}

	return total;
}

long long solve(int i)
{
	if (mem.count(i))
		return mem[i];

	if (i == all.size())
		return mem[i] = 0;

	vector<int> r;
	vector<int> b;

	int index = i;
	while (index < all.size() && all[index].second == all[i].second)
	{
		r.push_back(all[index].first);
		index++;
	}

	reverse(r.begin(), r.end());

	ll result = inf;

	while (index < all.size() && all[index].second != all[i].second)
	{
		b.push_back(all[index].first);

		ll cost = match(r, b);
		result = min(result, cost + min(solve(index), solve(index + 1)));

		index++;
	}

	return mem[i] = result;
}

long long min_total_length(std::vector<int> r, std::vector<int> b)
{
	all.clear();
	mem.clear();

	int n = r.size();
	int m = b.size();

	for (int i : r)
		all.push_back({i, -1});

	for (int i : b)
		all.push_back({i, 1});

	sort(all.begin(), all.end());

	vector<vector<int>> pockets;
	pockets.push_back({all[0].first});

	int index = all.size() - 1;

	for (int i = 1; i < n + m; i++)
	{
		if (all[i].second != all[i - 1].second)
			pockets.push_back({});
		pockets.back().push_back(all[i].first);
	}

	vector<int> last_pocket;
	vector<ll> last_scores;
	ll last_skip = 0;

	for (int i = pockets.size() - 1; i >= 0; i--)
	{

		int n = pockets[i].size();
		vector<ll> scores(n, inf);

		if (last_pocket.size() > 0)
		{
			vector<int> pocket = pockets[i];

			vector<ll> last1 = last_scores;
			vector<ll> last2 = last_scores;

			last1.pop_back();
			last2.erase(last2.begin());

			assert(last1.size() == last_pocket.size());

			ll additional = 0;
			for (int i = 0; i < last_pocket.size(); i++)
			{
				additional += last_pocket[i] - pocket.back();
				last1[i] += additional;
				last2[i] += additional;
			}

			LzySegtree<ll> segte1(last1);
			LzySegtree<ll> segte2(last2);

			scores[pocket.size() - 1] = min(segte1.segGet(0, segte1.n, 0, 0, segte1.n), segte2.segGet(0, segte2.n, 0, 0, segte2.n));
			// assert(scores[pocket.size() - 1] == solve(index));
			int first_index = pocket.back();
			pocket.pop_back();
			index--;
			int count = 1;

			while (pocket.size())
			{
				int current = pocket.back();
				count++;

				segte1.segUpdate(0, segte1.n, 0, count - 1, segte1.n, first_index - current);
				segte2.segUpdate(0, segte2.n, 0, count - 1, segte2.n, first_index - current);

				segte1.segUpdate(0, segte1.n, 0, 0, count - 1, last_pocket[0] - current);
				segte2.segUpdate(0, segte2.n, 0, 0, count - 1, last_pocket[0] - current);

				scores[pocket.size() - 1] = min(segte1.segGet(0, segte1.n, 0, 0, segte1.n), segte2.segGet(0, segte2.n, 0, 0, segte2.n));
				// assert(scores[pocket.size() - 1] == solve(index));
				pocket.pop_back();
				index--;
			}
		}
		else
		{
			index -= pockets[i].size();
		}

		scores.push_back(last_skip);

		if (last_pocket.size() > 0)
			last_skip = scores[0];
		else
			last_skip = inf;

		last_scores = scores;

		last_pocket = pockets[i];
	}

	// assert(last_scores[0] == solve(0));

	return last_scores[0];
}

#ifdef _DEBUG

int main()
{
	int n, m;

	int cnt;
	cin >> cnt;
	// assert(2 == scanf("%d %d", &n, &m));

	// vector<int> r(n), b(m);
	// for (int i = 0; i < n; i++)
	// 	assert(1 == scanf("%d", &r[i]));
	// for (int i = 0; i < m; i++)
	// 	assert(1 == scanf("%d", &b[i]));

	while (true)
	{

		vector<int> r, b;

		for (int i = 0; i < cnt; i++)
		{
			if (rand() % 2)
			{
				b.push_back(i);
			}
			else
			{
				r.push_back(i);
			}
		}

		assert(r.size() > 0);
		assert(b.size() > 0);

		long long res = min_total_length(r, b);
		printf("%lld\n", res);
	}

	return 0;
}

#endif

Compilation message (stderr)

wiring.cpp: In function 'long long int solve(int)':
wiring.cpp:113:8: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<std::pair<int, int> >::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  113 |  if (i == all.size())
      |      ~~^~~~~~~~~~~~~
wiring.cpp:120:15: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<std::pair<int, int> >::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  120 |  while (index < all.size() && all[index].second == all[i].second)
      |         ~~~~~~^~~~~~~~~~~~
wiring.cpp:130:15: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<std::pair<int, int> >::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  130 |  while (index < all.size() && all[index].second != all[i].second)
      |         ~~~~~~^~~~~~~~~~~~
wiring.cpp: In function 'long long int min_total_length(std::vector<int>, std::vector<int>)':
wiring.cpp:194:22: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  194 |    for (int i = 0; i < last_pocket.size(); i++)
      |                    ~~^~~~~~~~~~~~~~~~~~~~
#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...