Submission #1244373

#TimeUsernameProblemLanguageResultExecution timeMemory
1244373viduxScales (IOI15_scales)C++17
100 / 100
35 ms516 KiB
#include "scales.h"
#include "bits/stdc++.h"
using namespace std;
#define ALL(x) (x.begin()), (x.end())
#define RALL(x) (x.rbegin()), (x.rend())
#define SZ(x) ((int)x.size())
#define fi first
#define se second
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef array<int, 5> arr5;

vvi perm;
vector<array<int, 6>> permPos(720);
int pow3[7];
void init(int T) {
	pow3[0] = 1;
	for (int i = 1; i < 7; i++) pow3[i] = pow3[i-1]*3; 
	vi p = {0, 1, 2, 3, 4, 5};
	do { perm.push_back(p); } while(next_permutation(ALL(p)));
	for (int i = 0; i < 720; i++) {
		for (int j = 0; j < 6; j++) {
			permPos[i][perm[i][j]] = j;
		}
	}
	
}

vvi split(vi &alive, arr5 q) {
	auto [op, a, b, c, d] = q;
	vvi ret(3);
	for (int p : alive) {
		vector<pii> v = {
			{permPos[p][a], a},
			{permPos[p][b], b},
			{permPos[p][c], c}
		};
		sort(ALL(v));
		int idx = 0;
		if (op == 0) idx = (v[0].se == a) ? 0 : ((v[0].se == b) ? 1 : 2);
		if (op == 1) idx = (v[1].se == a) ? 0 : ((v[1].se == b) ? 1 : 2);
		if (op == 2) idx = (v[2].se == a) ? 0 : ((v[2].se == b) ? 1 : 2);
		if (op == 3) {
			int posa = permPos[p][a];
			int posb = permPos[p][b];
			int posc = permPos[p][c];
			int posd = permPos[p][d];
			vector<pii> v2;
			if (posa > posd) v2.push_back({posa, a});
			if (posb > posd) v2.push_back({posb, b});
			if (posc > posd) v2.push_back({posc, c});
			sort(ALL(v2));
			if (SZ(v2)) idx = (v2[0].se == a) ? 0 : ((v2[0].se == b) ? 1 : 2);
			else idx = (v[0].se == a) ? 0 : ((v[0].se == b) ? 1 : 2);
		}
		ret[idx].push_back(p);
	}
	return ret;
}

map<vi, arr5> dp;
arr5 solve(vi alive, int depth) {
	if (dp.find(alive) != dp.end()) return dp[alive];
	if (depth == 0) return (alive.size() <= 1) ? arr5{0} : arr5{-1};
	if (SZ(alive) > pow3[depth]) return {-1};
	vector<pair<int, arr5>> possible;
	for (int op = 0; op < 4; op++) {
		for (int a = 0; a < 6; a++) {
			for (int b = a+1; b < 6; b++) {
				for (int c = b+1; c < 6; c++) {
					if (op < 3) {
						int mx = 0;
						vvi sp = split(alive, {op, a, b, c, -1});
						for (int i = 0; i < 3; i++) mx = max(mx, SZ(sp[i]));
						if (mx <= pow3[depth-1]) possible.push_back({mx, {op, a, b, c, -1}});
					}
					else {
						for (int d = 0; d < 6; d++) if (d != a && d != b && d != c) {
							int mx = 0;
							vvi sp = split(alive, {op, a, b, c, d});
							for (int i = 0; i < 3; i++) mx = max(mx, SZ(sp[i]));
							if (mx <= pow3[depth-1]) possible.push_back({mx, {op, a, b, c, d}});
						}
					}
				}
			}
		}
	}
	sort(ALL(possible));
	for (auto [mx, q] : possible) {
		vvi sp = split(alive, q);
		bool ok = 1;
		for (int i = 0; i < 3; i++) {
			if (solve(sp[i], depth-1)[0] == -1) {
				ok = 0;
				break;
			}
		}
		if (ok) return dp[alive] = q;
	}
	return {-1};
}

void orderCoins() {
	vi alive(720);
	for (int i = 0; i < 720; i++) alive[i] = i;
	solve(alive, 6);
	int depth = 6;
	while (SZ(alive) > 1) {
		arr5 q = solve(alive, depth);
		auto [op, a, b, c, d] = q;
		a++, b++, c++, d++;
		int res = 0;
		if (op == 0) res = getLightest(a, b, c);
		if (op == 1) res = getMedian(a, b, c);
		if (op == 2) res = getHeaviest(a, b, c);
		if (op == 3) res = getNextLightest(a, b, c, d);
		vvi sp = split(alive, q);
		res = (res == a) ? 0 : ((res == b) ? 1 : 2);
		alive = sp[res];
		depth--;
	}
	int ans[6] = {0};
	for (int i = 0; i < 6; i++) ans[i] = perm[alive[0]][i]+1;
	//for (int i = 0; i < 6; i++) cout << ans[i] << " "; cout << endl;
	answer(ans);
}
#Verdict Execution timeMemoryGrader output
Fetching results...