#include <bits/stdc++.h>
using namespace std;

// Cooperative corridor mapping.
//
// The maze is a spanning tree over an m x m grid of "rooms" (m = (n+1)/2).
// Rooms live at (odd,odd) grid cells and are ALWAYS empty; (even,even) cells
// are ALWAYS walls. The only cells that carry information are the "corridor"
// cells with exactly one even coordinate, one between each pair of adjacent
// rooms. There are exactly 2*m*(m-1) of them = (n^2-1)/2.
//
// Every agent queries a disjoint stripe of the corridor list, base-95 packs its
// answer bits, and ships them to agent 0. Agent 0 reassembles the full corridor
// bitmap, BFS's the room tree from (0,0) to (m-1,m-1), and claims. This queries
// ~half of what solve_fullmap queries (it never touches rooms or walls).

struct Big {
    vector<uint32_t> limb;
    void trim() { while (!limb.empty() && limb.back() == 0) limb.pop_back(); }
    void shl1_or(int bit) {
        uint64_t carry = bit;
        for (uint32_t &x : limb) { uint64_t cur = (uint64_t)x * 2 + carry; x = (uint32_t)cur; carry = cur >> 32; }
        if (carry) limb.push_back((uint32_t)carry);
    }
    void mul_small_add(uint32_t mul, uint32_t add) {
        uint64_t carry = add;
        for (uint32_t &x : limb) { uint64_t cur = (uint64_t)x * mul + carry; x = (uint32_t)cur; carry = cur >> 32; }
        if (carry) limb.push_back((uint32_t)carry);
    }
    uint32_t div_small(uint32_t div) {
        uint64_t rem = 0;
        for (int i = (int)limb.size() - 1; i >= 0; --i) { uint64_t cur = (rem << 32) | limb[i]; limb[i] = (uint32_t)(cur / div); rem = cur % div; }
        trim(); return (uint32_t)rem;
    }
    bool bit(int pos) const { int w = pos / 32, b = pos % 32; return w < (int)limb.size() && ((limb[w] >> b) & 1u); }
    int bit_length() const { if (limb.empty()) return 0; uint32_t high = limb.back(); return ((int)limb.size() - 1) * 32 + (32 - __builtin_clz(high)); }
};

static int owned_count(int total, int agents, int id) {
    if (id >= total) return 0;
    return (total - 1 - id) / agents + 1;
}
static int bits_per_message(int len) {
    Big capacity; capacity.limb.push_back(1);
    for (int i = 0; i < len; ++i) capacity.mul_small_add(95, 0);
    return capacity.bit_length() - 1;
}
static string encode_chunk(const vector<unsigned char> &bits, int from, int count, int len) {
    Big x; for (int i = 0; i < count; ++i) x.shl1_or(bits[from + i]);
    string body(len, ' ');
    for (int i = len - 1; i >= 0; --i) { int digit = (int)x.div_small(95); body[i] = char(32 + digit); }
    return body;
}
static vector<unsigned char> decode_chunk(const string &body, int count) {
    Big x; for (unsigned char ch : body) { if (ch < 32 || ch > 126) continue; x.mul_small_add(95, int(ch - 32)); }
    vector<unsigned char> bits; bits.reserve(count);
    for (int i = count - 1; i >= 0; --i) bits.push_back(x.bit(i) ? 1 : 0);
    return bits;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, num_agents, agent_id, max_msg_len;
    if (!(cin >> n >> num_agents >> agent_id >> max_msg_len)) return 0;

    if (n == 1) {
        if (agent_id == 0) cout << "! " << endl; else cout << "halt" << endl;
        return 0;
    }
    if (max_msg_len <= 0) { cout << "halt" << endl; return 0; }

    const int m = (n + 1) / 2;              // rooms per side
    const int H = m * (m - 1);              // horizontal corridors
    const int V = (m - 1) * m;              // vertical corridors
    const int total = H + V;                // == (n^2-1)/2

    // Map a global corridor index -> grid cell to query.
    // idx in [0,H): horizontal, connects room(i,j)-(i,j+1), i in [0,m), j in [0,m-1).
    //   cell = (2i+1, 2j+2)
    // idx-H in [0,V): vertical, connects room(i,j)-(i+1,j), i in [0,m-1), j in [0,m).
    //   cell = (2i+2, 2j+1)
    auto corridor_cell = [&](int idx, int &gr, int &gc) {
        if (idx < H) { int i = idx / (m - 1), j = idx % (m - 1); gr = 2 * i + 1; gc = 2 * j + 2; }
        else { int k = idx - H, i = k / m, j = k % m; gr = 2 * i + 2; gc = 2 * j + 1; }
    };

    auto query = [&](int r, int c) {
        cout << "? " << r << ' ' << c << endl;
        string reply;
        if (!(cin >> reply)) exit(0);
        return (unsigned char)(reply == "1");
    };

    // --- Phase 1: every agent queries its stripe of corridors ---
    vector<unsigned char> my_bits;
    my_bits.reserve(owned_count(total, num_agents, agent_id));
    for (int idx = agent_id; idx < total; idx += num_agents) {
        int gr, gc; corridor_cell(idx, gr, gc);
        my_bits.push_back(query(gr, gc));
    }

    const int per_message = bits_per_message(max_msg_len);

    // --- Phase 2 (non-zero agents): ship bits to agent 0, then halt ---
    if (agent_id != 0) {
        for (int pos = 0; pos < (int)my_bits.size(); pos += per_message) {
            int take = min(per_message, (int)my_bits.size() - pos);
            cout << "> 0 " << encode_chunk(my_bits, pos, take, max_msg_len) << endl;
            string reply;
            if (!(cin >> reply)) return 0;
        }
        cout << "halt" << endl;
        return 0;
    }

    // --- Phase 2 (agent 0): reassemble full corridor bitmap ---
    vector<unsigned char> open(total, 0);
    { int p = 0; for (int idx = 0; idx < total; idx += num_agents) open[idx] = my_bits[p++]; }

    vector<vector<string>> msgs(num_agents);
    vector<int> remaining(num_agents, 0);
    int total_remaining = 0;
    for (int id = 1; id < num_agents; ++id) {
        int cnt = owned_count(total, num_agents, id);
        remaining[id] = (cnt + per_message - 1) / per_message;
        total_remaining += remaining[id];
        msgs[id].reserve(remaining[id]);
    }

    string line;
    while (total_remaining > 0) {
        cout << "< ?" << endl;
        if (!getline(cin >> ws, line)) return 0;
        if (line == "- -") continue;
        size_t sep = line.find(' ');
        if (sep == string::npos) continue;
        int sender = stoi(line.substr(0, sep));
        string body = line.substr(sep + 1);
        if (1 <= sender && sender < num_agents && remaining[sender] > 0) {
            msgs[sender].push_back(body);
            --remaining[sender];
            --total_remaining;
        }
    }

    for (int id = 1; id < num_agents; ++id) {
        int cnt = owned_count(total, num_agents, id);
        vector<unsigned char> bits; bits.reserve(cnt);
        for (const string &body : msgs[id]) {
            int take = min(per_message, cnt - (int)bits.size());
            auto chunk = decode_chunk(body, take);
            bits.insert(bits.end(), chunk.begin(), chunk.end());
        }
        int p = 0;
        for (int idx = id; idx < total; idx += num_agents) open[idx] = bits[p++];
    }

    // --- Phase 3: BFS the room tree, reconstruct path ---
    auto h_open = [&](int i, int j) { return open[i * (m - 1) + j] != 0; };        // room(i,j)-(i,j+1)
    auto v_open = [&](int i, int j) { return open[H + i * m + j] != 0; };          // room(i,j)-(i+1,j)

    vector<vector<char>> seen(m, vector<char>(m, 0));
    vector<vector<pair<int,int>>> parent(m, vector<pair<int,int>>(m, {-1,-1}));
    vector<vector<char>> pstep(m, vector<char>(m, 0));
    queue<pair<int,int>> q;
    seen[0][0] = 1; q.push({0, 0});
    while (!q.empty() && !seen[m-1][m-1]) {
        auto [i, j] = q.front(); q.pop();
        // R
        if (j + 1 < m && h_open(i, j) && !seen[i][j+1]) { seen[i][j+1]=1; parent[i][j+1]={i,j}; pstep[i][j+1]='R'; q.push({i,j+1}); }
        // L
        if (j - 1 >= 0 && h_open(i, j-1) && !seen[i][j-1]) { seen[i][j-1]=1; parent[i][j-1]={i,j}; pstep[i][j-1]='L'; q.push({i,j-1}); }
        // D
        if (i + 1 < m && v_open(i, j) && !seen[i+1][j]) { seen[i+1][j]=1; parent[i+1][j]={i,j}; pstep[i+1][j]='D'; q.push({i+1,j}); }
        // U
        if (i - 1 >= 0 && v_open(i-1, j) && !seen[i-1][j]) { seen[i-1][j]=1; parent[i-1][j]={i,j}; pstep[i-1][j]='U'; q.push({i-1,j}); }
    }

    if (!seen[m-1][m-1]) { cout << "halt" << endl; return 0; }

    string room_path;
    for (int i = m-1, j = m-1; !(i == 0 && j == 0);) {
        room_path.push_back(pstep[i][j]);
        auto [pi, pj] = parent[i][j];
        i = pi; j = pj;
    }
    reverse(room_path.begin(), room_path.end());

    string grid_path; grid_path.reserve(room_path.size() * 2);
    for (char ch : room_path) { grid_path.push_back(ch); grid_path.push_back(ch); }

    cout << "! " << grid_path << endl;
    return 0;
}
