/// 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;
}