Submission #749760

# Submission time Handle Problem Language Result Execution time Memory
749760 2023-05-28T12:47:35 Z SanguineChameleon Alice, Bob, and Circuit (APIO23_abc) C++17
100 / 100
681 ms 291364 KB
#include <bits/stdc++.h>
#include "abc.h"
using namespace std;

// you may find the definitions useful
const int OP_ZERO    = 0;  // f(OP_ZERO,    x0, x1) = 0
const int OP_NOR     = 1;  // f(OP_NOR,     x0, x1) = !(x0 || x1)
const int OP_GREATER = 2;  // f(OP_GREATER, x0, x1) = (x0 > x1)
const int OP_NOT_X1  = 3;  // f(OP_NOT_X1,  x0, x1) = !x1
const int OP_LESS    = 4;  // f(OP_LESS,    x0, x1) = (x0 < x1)
const int OP_NOT_X0  = 5;  // f(OP_NOT_X0,  x0, x1) = !x0
const int OP_XOR     = 6;  // f(OP_XOR,     x0, x1) = (x0 ^ x1)
const int OP_NAND    = 7;  // f(OP_NAND,    x0, x1) = !(x0 && x1)
const int OP_AND     = 8;  // f(OP_AND,     x0, x1) = (x0 && x1)
const int OP_EQUAL   = 9;  // f(OP_EQUAL,   x0, x1) = (x0 == x1)
const int OP_X0      = 10; // f(OP_X0,      x0, x1) = x0
const int OP_GEQ     = 11; // f(OP_GEQ,     x0, x1) = (x0 >= x1)
const int OP_X1      = 12; // f(OP_X1,      x0, x1) = x1
const int OP_LEQ     = 13; // f(OP_LEQ,     x0, x1) = (x0 <= x1)
const int OP_OR      = 14; // f(OP_OR,      x0, x1) = (x0 || x1)
const int OP_ONE     = 15; // f(OP_ONE,     x0, x1) = 1

int encode(string s) {
	int res = 0;
	for (auto c: s) {
		res = res * 26 + (c - 'a');
	}
	int pw = 1;
	for (int i = 1; i <= (int)s.size() - 1; i++) {
		pw = pw * 26;
		res += pw;
	}
	return res;
}

vector<int> build(vector<int> a) {
	int n = a.size();
	if (n <= 1) {
		return vector<int>();
	}
	vector<int> pos(n);
	for (int i = 0; i < n; i++) {
		pos[a[i]] = i;
	}
	vector<vector<pair<int, int>>> adj(n);
	vector<int> swap1(n / 2, -1);
	vector<int> swap2(n / 2, -1);
	for (int i = 0; i < n / 2; i++) {
		int x = pos[i];
		int y = pos[n / 2 + i];
		if (n % 2 == 1 && (x == n - 1 || y == n - 1)) {
			continue;
		}
		int u = (x < n / 2 ? x : x - n / 2);
		int v = (y < n / 2 ? y : y - n / 2);
		int w = (x < n / 2) ^ (y < n / 2) ^ 1;
		adj[u].emplace_back(v, w);
		adj[v].emplace_back(u, w);
	}
	if (n % 2 == 1 && pos[n - 1] != n - 1) {
		int cur = (pos[n - 1] < n / 2 ? pos[n - 1] : pos[n - 1] - n / 2);
		swap1[cur] = (pos[n - 1] < n / 2);
		while (true) {
			bool found = false;
			for (auto e: adj[cur]) {
				int nxt = e.first;
				int w = e.second;
				if (swap1[nxt] == -1) {
					swap1[nxt] = swap1[cur] ^ w;
					cur = nxt;
					found = true;
					break;
				}
			}
			if (!found) {
				break;
			}
		}
	}
	for (int i = 0; i < n / 2; i++) {
		if (swap1[i] == -1) {
			int cur = i;
			swap1[cur] = 0;
			while (true) {
				bool found = false;
				for (auto e: adj[cur]) {
					int nxt = e.first;
					int w = e.second;
					if (swap1[nxt] == -1) {
						swap1[nxt] = swap1[cur] ^ w;
						cur = nxt;
						found = true;
						break;
					}
				}
				if (!found) {
					break;
				}
			}
		}
	}
	vector<int> al(a.begin(), a.begin() + n / 2);
	vector<int> ar(a.begin() + n / 2, a.end());
	for (int i = 0; i < n / 2; i++) {
		if (swap1[i]) {
			swap(al[i], ar[i]);
		}
	}
	for (int i = 0; i < n / 2; i++) {
		if (al[i] < n / 2) {
			swap2[al[i]] = 0;
		}
		else {
			al[i] -= n / 2;
			swap2[al[i]] = 1;
		}
	}
	for (int i = 0; i < n - n / 2; i++) {
		if (ar[i] >= n / 2) {
			ar[i] -= n / 2;
		}
	}
	vector<int> fl = build(al);
	vector<int> fr = build(ar);
	vector<int> res(swap1.begin(), swap1.end());
	res.insert(res.end(), fl.begin(), fl.end());
	res.insert(res.end(), fr.begin(), fr.end());
	res.insert(res.end(), swap2.begin(), swap2.end());
	return res;
}

int calc(int n) {
	if (n <= 1) {
		return 0;
	}
	return calc(n / 2) + calc(n - n / 2) + (n / 2) * 2;
}

// Alice
int // returns la
alice(
	/*  in */ const int n,
	/*  in */ const char names[][5],
	/*  in */ const unsigned short numbers[],
	/* out */ bool outputs_alice[]
) {
	vector<pair<int, int>> order(n);
	for (int i = 0; i < n; i++) {
		order[i] = make_pair(encode(names[i]), i);
	}
	sort(order.begin(), order.end());
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < 19; j++) {
			outputs_alice[i * 35 + j] = (order[i].first >> j) & 1;
		}
		for (int j = 0; j < 16; j++) {
			outputs_alice[i * 35 + 19 + j] = (numbers[order[i].second] >> j) & 1;
		}
	}
	vector<int> perm(n);
	for (int i = 0; i < n; i++) {
		perm[i] = order[i].second;
	}
	vector<int> flag = build(perm);
	int sz = flag.size();
	for (int i = 0; i < sz; i++) {
		outputs_alice[n * 35 + i] = flag[i];
	}
	return n * 35 + sz;
}


// Bob
int // returns lb
bob(
	/*  in */ const int m,
	/*  in */ const char senders[][5],
	/*  in */ const char recipients[][5],
	/* out */ bool outputs_bob[]
) {
	vector<pair<int, int>> order1(m);
	for (int i = 0; i < m; i++) {
		order1[i] = make_pair(encode(recipients[i]), encode(senders[i]));
	}
	sort(order1.begin(), order1.end());
	vector<pair<pair<int, int>, int>> order2(m);
	for (int i = 0; i < m; i++) {
		order2[i] = make_pair(make_pair(order1[i].second, order1[i].first), i);
	}
	sort(order2.begin(), order2.end());
	for (int i = 0; i < m; i++) {
		for (int j = 0; j < 19; j++) {
			outputs_bob[i * 38 + j] = (order2[i].first.first >> j) & 1;
		}
		for (int j = 0; j < 19; j++) {
			outputs_bob[i * 38 + 19 + j] = (order2[i].first.second >> j) & 1;
		}
	}
	vector<int> perm(m);
	for (int i = 0; i < m; i++) {
		perm[i] = order2[i].second;
	}
	vector<int> flag = build(perm);
	int sz = flag.size();
	for (int i = 0; i < sz; i++) {
		outputs_bob[m * 38 + i] = flag[i];
	}
	return m * 38 + sz;
}

int *operations;
int (*operands)[2];
int ZERO_GATE;
int ONE_GATE;
int gate_cnt;

int gate(int op, int x, int y) {
	operations[gate_cnt] = op;
	operands[gate_cnt][0] = x;
	operands[gate_cnt][1] = y;
	return gate_cnt++;
}

pair<int, int> add(int x, int y, int z) {
	int sum1 = gate(OP_XOR, x, y);
	int rem1 = gate(OP_AND, x, y);
	int sum2 = gate(OP_XOR, sum1, z);
	int rem2 = gate(OP_AND, sum1, z);
	return make_pair(sum2, gate(OP_OR, rem1, rem2));
}

vector<int> add(vector<int> num1, vector<int> num2) {
	vector<int> res(16);
	int rem = ZERO_GATE;
	for (int i = 0; i < 16; i++) {
		auto p = add(num1[i], num2[i], rem);
		res[i] = p.first;
		rem = p.second;
	}
	return res;
}

vector<int> mul(vector<int> num, int x) {
	vector<int> res(16);
	for (int i = 0; i < 16; i++) {
		res[i] = gate(OP_AND, num[i], x);
	}
	return res;
}

vector<int> mul_flip(vector<int> num, int x) {
	vector<int> res(16);
	for (int i = 0; i < 16; i++) {
		res[i] = gate(OP_GREATER, num[i], x);
	}
	return res;
}

vector<int> _xor(vector<int> num1, vector<int> num2) {
	vector<int> res(16);
	for (int i = 0; i < 16; i++) {
		res[i] = gate(OP_XOR, num1[i], num2[i]);
	}
	return res;
}

struct event {
	int type;
	bool fake;
	vector<int> name1, name2, val;

	event(): type(-1), fake(true) {};
};

vector<event> events;
vector<pair<int, int>> swaps;
vector<int> flag;

void build(int lt, int rt) {
	int n = rt - lt + 1;
	if (n <= 1) {
		return;
	}
	for (int i = 0; i < n / 2; i++) {
		swaps.emplace_back(lt + i, lt + n / 2 + i);
	}
	build(lt, lt + n / 2 - 1);
	build(lt + n / 2, rt);
	for (int i = 0; i < n / 2; i++) {
		swaps.emplace_back(lt + i, lt + n / 2 + i);
	}
}

void swap(int &x, int &y, int f) {
	int z = gate(OP_AND, gate(OP_XOR, x, y), f);
	x = gate(OP_XOR, x, z);
	y = gate(OP_XOR, y, z);
}

int comp(int x, int y) {
	if (events[y].fake) {
		return ZERO_GATE;
	}
	if (events[x].fake) {
		return ONE_GATE;
	}
	int equal = ONE_GATE;
	int res = ZERO_GATE;
	for (int i = 18; i >= 0; i--) {
		res = gate(OP_OR, res, gate(OP_AND, equal, gate(OP_GREATER, events[x].name1[i], events[y].name1[i])));
		equal = gate(OP_AND, equal, gate(OP_EQUAL, events[x].name1[i], events[y].name1[i]));
	}
	res = gate(OP_OR, res, gate(OP_AND, equal, gate(OP_GREATER, events[x].type, events[y].type)));
	equal = gate(OP_AND, equal, gate(OP_EQUAL, events[x].type, events[y].type));
	return res;
}

void shuffle() {
	int sz = swaps.size();
	for (int i = 0; i < sz; i++) {
		int x = swaps[i].first;
		int y = swaps[i].second;
		if (flag[i] == -1) {
			flag[i] = comp(x, y);
		}
		if (flag[i] == ZERO_GATE) {
			continue;
		}
		if (flag[i] == ONE_GATE) {
			swap(events[x], events[y]);
			continue;
		}
		for (int j = 0; j < 19; j++) {
			swap(events[x].name1[j], events[y].name1[j], flag[i]);
			swap(events[x].name2[j], events[y].name2[j], flag[i]);
		}
		for (int j = 0; j < 16; j++) {
			swap(events[x].val[j], events[y].val[j], flag[i]);
		}
		swap(events[x].type, events[y].type, flag[i]);
	}
}

void merge(int x, int y, int step) {
	if (x + step == y) {
		swaps.emplace_back(x, y);
		return;
	}
	merge(x, y, step * 2);
	merge(x + step, y + step, step * 2);
	x += step;
	while (x + step < 2048) {
		swaps.emplace_back(x, x + step);
		x += step * 2;
	}
}

// Circuit
int // returns l
circuit(
	/*  in */ const int la,
	/*  in */ const int lb,
	/* out */ int _operations[],
	/* out */ int _operands[][2],
	/* out */ int outputs_circuit[][16]
) {
	operations = _operations;
	operands = _operands;
	gate_cnt = la + lb;
	ZERO_GATE = gate(OP_ZERO, 0, 0);
	ONE_GATE = gate(OP_ONE, 0, 0);
	int n = 0;
	while (n * 35 + calc(n) < la) {
		n++;
	}
	int m = 0;
	while (m * 38 + calc(m) < lb) {
		m++;
	}
	events.resize(2048);
	for (int i = 0; i < n; i++) {
		events[i].name1.resize(19);
		events[i].name2.resize(19);
		events[i].val.resize(16);
		for (int j = 0; j < 19; j++) {
			events[i].name1[j] = i * 35 + j;
			events[i].name2[j] = i * 35 + j;
		}
		for (int j = 0; j < 16; j++) {
			events[i].val[j] = i * 35 + 19 + j;
		}
		events[i].type = ZERO_GATE;
		events[i].fake = false;
	}
	for (int i = 0; i < m; i++) {
		events[1024 + i].name1.resize(19);
		events[1024 + i].name2.resize(19);
		events[1024 + i].val.resize(16, ZERO_GATE);
		for (int j = 0; j < 19; j++) {
			events[1024 + i].name1[j] = la + i * 38 + j;
			events[1024 + i].name2[j] = la + i * 38 + 19 + j;
		}
		events[1024 + i].type = ONE_GATE;
		events[1024 + i].fake = false;
	}
	merge(0, 1024, 1);
	flag.resize(swaps.size(), -1);
	shuffle();
	vector<int> cur(16, ZERO_GATE);
	for (int i = 0; i < n + m; i++) {
		cur = _xor(cur, mul_flip(_xor(cur, events[i].val), events[i].type));
		events[i].val = cur;
		swap(events[i].name1, events[i].name2);
	}
	reverse(swaps.begin(), swaps.end());
	reverse(flag.begin(), flag.end());
	shuffle();
	swaps.clear();
	flag.clear();
	build(1024, 1024 + m - 1);
	flag.resize(swaps.size());
	for (int i = 0; i < (int)flag.size(); i++) {
		flag[i] = la + m * 38 + i;
	}
	shuffle();
	swaps.clear();
	flag.clear();
	merge(0, 1024, 1);
	flag.resize(swaps.size(), -1);
	shuffle();
	cur.clear();
	cur.resize(16, ZERO_GATE);
	for (int i = n + m - 1; i >= 0; i--) {
		swap(cur, events[i].val);
		cur = mul(add(cur, events[i].val), events[i].type);
	}
	reverse(swaps.begin(), swaps.end());
	reverse(flag.begin(), flag.end());
	shuffle();
	swaps.clear();
	flag.clear();
	build(0, n - 1);
	flag.resize(swaps.size());
	for (int i = 0; i < (int)flag.size(); i++) {
		flag[i] = n * 35 + i;
	}
	shuffle();
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < 16; j++) {
			outputs_circuit[i][j] = events[i].val[j];
		}
	}
	return gate_cnt;
}
# Verdict Execution time Memory Grader output
1 Correct 3 ms 1352 KB Correct!
# Verdict Execution time Memory Grader output
1 Correct 3 ms 1352 KB Correct!
2 Correct 3 ms 1436 KB Correct!
# Verdict Execution time Memory Grader output
1 Correct 3 ms 1352 KB Correct!
2 Correct 3 ms 1436 KB Correct!
3 Correct 331 ms 150800 KB Correct!
4 Correct 348 ms 151416 KB Correct!
# Verdict Execution time Memory Grader output
1 Correct 12 ms 4980 KB Correct!
2 Correct 209 ms 76692 KB Correct!
3 Correct 234 ms 103444 KB Correct!
# Verdict Execution time Memory Grader output
1 Correct 12 ms 4980 KB Correct!
2 Correct 209 ms 76692 KB Correct!
3 Correct 234 ms 103444 KB Correct!
4 Correct 197 ms 76736 KB Correct!
5 Correct 243 ms 103224 KB Correct!
# Verdict Execution time Memory Grader output
1 Correct 12 ms 4980 KB Correct!
2 Correct 209 ms 76692 KB Correct!
3 Correct 234 ms 103444 KB Correct!
4 Correct 197 ms 76736 KB Correct!
5 Correct 243 ms 103224 KB Correct!
6 Correct 168 ms 65552 KB Correct!
7 Correct 352 ms 141608 KB Correct!
# Verdict Execution time Memory Grader output
1 Correct 657 ms 286144 KB Correct!
2 Correct 665 ms 286608 KB Correct!
# Verdict Execution time Memory Grader output
1 Correct 657 ms 286144 KB Correct!
2 Correct 665 ms 286608 KB Correct!
3 Correct 608 ms 265156 KB Correct!
4 Correct 661 ms 286588 KB Correct!
# Verdict Execution time Memory Grader output
1 Correct 3 ms 1352 KB Correct!
2 Correct 3 ms 1436 KB Correct!
3 Correct 331 ms 150800 KB Correct!
4 Correct 348 ms 151416 KB Correct!
5 Correct 12 ms 4980 KB Correct!
6 Correct 209 ms 76692 KB Correct!
7 Correct 234 ms 103444 KB Correct!
8 Correct 197 ms 76736 KB Correct!
9 Correct 243 ms 103224 KB Correct!
10 Correct 168 ms 65552 KB Correct!
11 Correct 352 ms 141608 KB Correct!
12 Correct 657 ms 286144 KB Correct!
13 Correct 665 ms 286608 KB Correct!
14 Correct 608 ms 265156 KB Correct!
15 Correct 661 ms 286588 KB Correct!
16 Correct 661 ms 291364 KB Correct!
17 Correct 681 ms 291320 KB Correct!