제출 #836594

#제출 시각아이디문제언어결과실행 시간메모리
836594happypotatoVision Program (IOI19_vision)C++17
100 / 100
13 ms1904 KiB
#include "vision.h"
#include <bits/stdc++.h>
using namespace std;
#define pb push_back

void construct_network(int n, int m, int k) {
	if (n * m == 2) {
		add_and({0, 1});
		return;
	}
	const int ZERO = add_and({0, 1, 2});
	const int ONE = add_not(ZERO);
	function<int(void)> add_zero = [&]() -> int { return add_and({ZERO}); };
	function<int(void)> add_one = [&]() -> int { return add_and({ONE}); };

	function<int(int, int)> hash = [&](int x, int y) -> int {
		return x * m + y;
	};
	function<bool(int, int)> valid = [&](int x, int y) -> bool {
		return ((0 <= x && x < n) && (0 <= y && y < m));
	};
	
	// stores position of min in range [st, en]
	function<int(int, int)> findmin = [&](int st, int en) -> int {
		int diff = en - st + 1;
		int prev = add_zero();
		for (int i = 1; i < 8; i++) add_zero();
		vector<int> allprev;
		int prevtakexor = add_zero();
		for (int cur = 1; cur <= diff; cur++) { // from min
			int pos = st + (cur - 1);
			// check if [prev, prev + 8) has value
			vector<int> prevs = {prevtakexor};
			for (int i = prev; i < prev + 8; i++) prevs.pb(i);
			prevtakexor = add_or(prevs);
			int takexor = add_not(prevtakexor); // 1 if prev = 0
			// assign (pos & takexor & (cur & (1 << i))) to prev
			int nxt = -1;
			for (int i = 0; i < 8; i++) {
				int res = add_and({pos, takexor, (bool(cur & (1 << i)) ? ONE : ZERO)});
				if (nxt == -1) nxt = res;
			}
			prev = nxt;
			allprev.pb(nxt);
		}
		// only 1 has value, take or
		int ret = -1;
		for (int i = 0; i < 8; i++) {
			vector<int> v;
			for (int &x : allprev) v.pb(x + i);
			int res = add_or(v);
			if (ret == -1) ret = res;
		}
		return ret;
	};
	// stores position of max in range [st, en]
	function<int(int, int)> findmax = [&](int st, int en) -> int {
		int diff = en - st + 1;
		int prev = add_zero();
		for (int i = 1; i < 8; i++) add_zero();
		vector<int> allprev;
		int prevtakexor = add_zero();
		for (int cur = diff; cur >= 1; cur--) { // from max
			int pos = st + (cur - 1);
			// check if [prev, prev + 8) has value
			vector<int> prevs = {prevtakexor};
			for (int i = prev; i < prev + 8; i++) prevs.pb(i);
			prevtakexor = add_or(prevs);
			int takexor = add_not(prevtakexor); // 1 if prev = 0
			// assign (pos & takexor & (cur & (1 << i))) to prev
			int nxt = -1;
			for (int i = 0; i < 8; i++) {
				int res = add_and({pos, takexor, (bool(cur & (1 << i)) ? ONE : ZERO)});
				if (nxt == -1) nxt = res;
			}
			prev = nxt;
			allprev.pb(nxt);
		}
		// only 1 has value, take or
		int ret = -1;
		for (int i = 0; i < 8; i++) {
			vector<int> v;
			for (int &x : allprev) v.pb(x + i);
			int res = add_or(v);
			if (ret == -1) ret = res;
		}
		return ret;
	};

	// addition modulo 2^10 = 1024
	function<vector<int>(vector<int>, vector<int>)> add = [&](vector<int> lhs, vector<int> rhs) -> vector<int> {
		vector<int> res;
		int prev = add_zero(); // carrying
		res.pb(add_xor({lhs[0], rhs[0]}));
		for (int i = 1; i < 10; i++) {
			// handle carrying:
			// (prev, lhs[i - 1], rhs[i - 1]) >= 2
			// (AND = 1) or (XOR = 0 and OR = 1)
			// (AND) or (XOR xor OR) (no case where (XOR = 1 and OR = 0))
			vector<int> check = {prev, lhs[i - 1], rhs[i - 1]};
			int isthree = add_and(check);
			int istwo = add_xor({add_xor(check), add_or(check)});
			int fincarry = add_or({isthree, istwo});
			prev = fincarry;
			// calculate current bit
			res.pb(add_xor({prev, lhs[i], rhs[i]}));
		}
		return res;
	};

	int st = -1, en = -1;
	// find vertical
	for (int i = 0; i < n; i++) {
		vector<int> v;
		for (int j = 0; j < m; j++) v.pb(hash(i, j));
		int res = add_or(v);
		if (i == 0) st = res;
		if (i == n - 1) en = res;
	}
	int vmini = findmin(st, en);
	int vmaxi = findmax(st, en);
	// find horizontal
	for (int i = 0; i < m; i++) {
		vector<int> v;
		for (int j = 0; j < n; j++) v.pb(hash(j, i));
		int res = add_or(v);
		if (i == 0) st = res;
		if (i == m - 1) en = res;
	}
	int hmini = findmin(st, en);
	int hmaxi = findmax(st, en);

	// cerr << vmini << ' ' << vmaxi << ' ' << hmini << ' ' << hmaxi << endl;

	//   (vmax - vmin) + (hmax - hmin)
	// = (vmax + (1023 - vmin)) + (hmax + (1023 - hmin)) + 2 (mod 1024)
	// = (vmax + (vmin ^ 1023)) + (hmax + (hmin ^ 1023)) + 2 (mod 1024)

	vector<int> vmax(10), vmin(10), hmax(10), hmin(10);
	vector<int> two(10);
	for (int i = 0; i < 10; i++) {
		// take xor with mins
		vmax[i] = (i < 8 ? vmaxi + i : ZERO);
		vmin[i] = (i < 8 ? add_not(vmini + i) : ONE);
		hmax[i] = (i < 8 ? hmaxi + i : ZERO);
		hmin[i] = (i < 8 ? add_not(hmini + i) : ONE);
		two[i] = (i == 1 ? ONE : ZERO);
	}
	vector<int> res1 = add(vmax, vmin);
	vector<int> res2 = add(hmax, hmin);
	vector<int> dist = add(add(res1, res2), two);
	// compare dist and k
	vector<int> fin;
	for (int i = 0; i < 10; i++) {
		fin.pb(add_xor({dist[i], (bool(k & (1 << i)) ? ONE : ZERO)}));
	}
	add_not(add_or(fin));
}
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...