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

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

    int n;
    ll X, Y, Z;
    cin >> n >> X >> Y >> Z;

    vector<Vec> v(n);
    // Nhận diện subtask 1 chiều (Quy hoạch động)
    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');

    // Giải bằng Knapsack + Bitset cho các test 1D
    if (is1D_X) {
        vector<bitset<1000005>> dp(n + 1);
        dp[0][0] = 1;
        for (int i = 0; i < n; i++) dp[i + 1] = dp[i] | (dp[i] << v[i].x);
        ll cur = X;
        for (int i = n - 1; i >= 0; i--) {
            if (cur >= v[i].x && dp[i][cur - v[i].x]) {
                ans[v[i].id] = '1';
                cur -= v[i].x;
            }
        }
        cout << ans << "\n";
        return 0;
    }

    if (is1D_Y) {
        vector<bitset<1000005>> dp(n + 1);
        dp[0][0] = 1;
        for (int i = 0; i < n; i++) dp[i + 1] = dp[i] | (dp[i] << v[i].y);
        ll cur = Y;
        for (int i = n - 1; i >= 0; i--) {
            if (cur >= v[i].y && dp[i][cur - v[i].y]) {
                ans[v[i].id] = '1';
                cur -= v[i].y;
            }
        }
        cout << ans << "\n";
        return 0;
    }

    if (is1D_Z) {
        vector<bitset<1000005>> dp(n + 1);
        dp[0][0] = 1;
        for (int i = 0; i < n; i++) dp[i + 1] = dp[i] | (dp[i] << v[i].z);
        ll cur = Z;
        for (int i = n - 1; i >= 0; i--) {
            if (cur >= v[i].z && dp[i][cur - v[i].z]) {
                ans[v[i].id] = '1';
                cur -= v[i].z;
            }
        }
        cout << ans << "\n";
        return 0;
    }

    // Giải bằng Backtracking + Pruning cho trường hợp 3D tổng quát
    sort(v.begin(), v.end(), [](const Vec& a, const Vec& b) {
        return a.x + a.y + a.z > b.x + b.y + b.z;
    });

    vector<ll> sufX(n + 1, 0), sufY(n + 1, 0), sufZ(n + 1, 0);
    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;
    }

    bool found = false;
    auto dfs = [&](auto& self, int idx, ll cx, ll cy, ll cz) -> void {
        if (found) return;
        if (cx == X && cy == Y && cz == Z) {
            found = true;
            return;
        }
        if (idx == n) return;
        // Nhánh cận: Nếu đã vượt quá mục tiêu
        if (cx > X || cy > Y || cz > Z) return;
        // Nhánh cận: Nếu cộng tất cả phần tử còn lại vẫn không đủ mục tiêu
        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);

    cout << ans << "\n";
    
    return 0;
}