/// no time to waste
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define eb emplace_back
#define pii pair <int, int>
#define pli pair <ll, int>
#define fi first
#define se second
#define all(ac) ac.begin(), ac.end()
#define MASK(x) (1 << x)
#define ub(i, j) ((i >> j) & 1)
#define FBIT(x) (MASK(x) - 1)
#define FLIP(x, y) (FBIT(x) ^ y)
#define ii make_pair
#define int128 __int128_t
struct Vec {
ll x, y, z;
int id;
};
struct State {
ll x, y, z;
ll mask;
bool operator<(const State& o) const {
if (x != o.x) return x < o.x;
if (y != o.y) return y < o.y;
return z < o.z;
}
bool operator==(const State& o) const {
return x == o.x && y == o.y && z == o.z;
}
};
int32_t main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
#define task "tet"
if(fopen(task".inp", "r")) {
freopen(task".inp", "r", stdin);
freopen(task".out", "w", stdout);
}
auto start_time = chrono::high_resolution_clock::now();
int n;
ll X, Y, Z;
cin >> n >> X >> Y >> Z;
vector<Vec> v(n);
bool is1D_X = (Y == 0 && Z == 0);
bool is1D_Y = (X == 0 && Z == 0);
bool is1D_Z = (X == 0 && Y == 0);
for (int i = 0; i < n; i++) {
cin >> v[i].x >> v[i].y >> v[i].z;
v[i].id = i;
if (v[i].y != 0 || v[i].z != 0) is1D_X = false;
if (v[i].x != 0 || v[i].z != 0) is1D_Y = false;
if (v[i].x != 0 || v[i].y != 0) is1D_Z = false;
}
string ans(n, '0');
// 1. Xử lý Subtask 1 chiều (Bitset DP)
if (is1D_X || is1D_Y || is1D_Z) {
vector<bitset<1000005>> dp(n + 1);
dp[0][0] = 1;
ll target = is1D_X ? X : (is1D_Y ? Y : Z);
for (int i = 0; i < n; i++) {
ll val = is1D_X ? v[i].x : (is1D_Y ? v[i].y : v[i].z);
dp[i + 1] = dp[i] | (dp[i] << val);
}
ll cur = target;
for (int i = n - 1; i >= 0; i--) {
ll val = is1D_X ? v[i].x : (is1D_Y ? v[i].y : v[i].z);
if (cur >= val && dp[i][cur - val]) {
ans[v[i].id] = '1';
cur -= val;
}
}
cout << ans << "\n";
return 0;
}
// 2. Xử lý N <= 40 (Meet-in-the-Middle)
if (n <= 40) {
int n1 = n / 2;
int n2 = n - n1;
vector<State> left_states;
left_states.reserve(MASK(n1));
for (ll mask = 0; mask < MASK(n1); mask++) {
ll cx = 0, cy = 0, cz = 0;
for (int i = 0; i < n1; i++) {
if (ub(mask, i)) {
cx += v[i].x; cy += v[i].y; cz += v[i].z;
}
}
if (cx <= X && cy <= Y && cz <= Z) {
left_states.push_back({cx, cy, cz, mask});
}
}
sort(all(left_states));
for (ll mask = 0; mask < MASK(n2); mask++) {
ll cx = 0, cy = 0, cz = 0;
for (int i = 0; i < n2; i++) {
if (ub(mask, i)) {
cx += v[n1 + i].x; cy += v[n1 + i].y; cz += v[n1 + i].z;
}
}
if (cx <= X && cy <= Y && cz <= Z) {
State target = {X - cx, Y - cy, Z - cz, 0};
auto it = lower_bound(all(left_states), target);
if (it != left_states.end() && *it == target) {
for (int i = 0; i < n1; i++) if (ub(it->mask, i)) ans[v[i].id] = '1';
for (int i = 0; i < n2; i++) if (ub(mask, i)) ans[v[n1 + i].id] = '1';
cout << ans << "\n";
return 0;
}
}
}
}
// 3. Xử lý 3D tổng quát (Randomized DFS)
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
bool found = false;
vector<ll> sufX(n + 1, 0), sufY(n + 1, 0), sufZ(n + 1, 0);
while (chrono::duration_cast<chrono::milliseconds>(chrono::high_resolution_clock::now() - start_time).count() < 900) {
shuffle(all(v), rng);
for (int i = n - 1; i >= 0; i--) {
sufX[i] = sufX[i + 1] + v[i].x;
sufY[i] = sufY[i + 1] + v[i].y;
sufZ[i] = sufZ[i + 1] + v[i].z;
}
int nodes_visited = 0;
int max_nodes = 5000; // Giới hạn số lần thử cho mỗi cấu hình shuffle
auto dfs = [&](auto& self, int idx, ll cx, ll cy, ll cz) -> void {
if (found || nodes_visited > max_nodes) return;
nodes_visited++;
if (cx == X && cy == Y && cz == Z) {
found = true;
return;
}
if (idx == n) return;
if (cx > X || cy > Y || cz > Z) return;
if (cx + sufX[idx] < X || cy + sufY[idx] < Y || cz + sufZ[idx] < Z) return;
ans[v[idx].id] = '1';
self(self, idx + 1, cx + v[idx].x, cy + v[idx].y, cz + v[idx].z);
if (found) return;
ans[v[idx].id] = '0';
self(self, idx + 1, cx, cy, cz);
};
dfs(dfs, 0, 0, 0, 0);
if (found) break;
}
if (found) cout << ans << "\n";
return 0;
}