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

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;
        int 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 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 int owned_count(int total, int agents, int id) {
    if (id >= total) {
        return 0;
    }
    return (total - 1 - id) / agents + 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;
}

struct Schedule {
    int score = 0;
    int agent0_queries = 0;
    int total_messages = 0;
    int known_cells = 0;
    vector<vector<int>> payloads;
    vector<vector<int>> send_slots;
    vector<int> cell_offset;
};

static Schedule build_schedule_for_messages(int score, int agents, int w, int total_cells, int total_messages) {
    int preclaim = score - 1;
    int q0 = preclaim - total_messages;
    Schedule s;
    s.score = score;
    s.agent0_queries = q0;
    s.total_messages = total_messages;
    s.known_cells = q0;
    s.payloads.assign(agents, {});
    s.send_slots.assign(agents, {});
    s.cell_offset.assign(agents, 0);

    vector<int> sent_count(agents, 0);
    vector<int> sent_bits(agents, 0);
    for (int slot = 0; slot < total_messages; ++slot) {
        int best_id = -1;
        int best_payload = 0;
        for (int id = 1; id < agents; ++id) {
            int queried_before_send = q0 + slot - 1 - sent_count[id];
            int available = queried_before_send - sent_bits[id];
            int payload = min(w, max(0, available));
            if (payload > best_payload) {
                best_payload = payload;
                best_id = id;
            }
        }
        if (best_id == -1 || best_payload <= 0) {
            s.known_cells = -1;
            return s;
        }

        int needed = total_cells - s.known_cells;
        int payload = min(best_payload, max(0, needed));
        s.payloads[best_id].push_back(payload);
        s.send_slots[best_id].push_back(slot);
        ++sent_count[best_id];
        sent_bits[best_id] += payload;
        s.known_cells += payload;
    }

    int offset = min(q0, total_cells);
    for (int id = 1; id < agents; ++id) {
        s.cell_offset[id] = offset;
        int bits = 0;
        for (int payload : s.payloads[id]) {
            bits += payload;
        }
        offset += bits;
    }
    return s;
}

static Schedule build_best_schedule(int score, int agents, int w, int total_cells) {
    int preclaim = score - 1;
    Schedule best;
    best.known_cells = -1;
    if (preclaim <= 0) {
        best.score = score;
        best.agent0_queries = 0;
        best.total_messages = 0;
        best.known_cells = 0;
        best.payloads.assign(agents, {});
        best.send_slots.assign(agents, {});
        best.cell_offset.assign(agents, 0);
        return best;
    }

    int optimistic_needed = max(0, total_cells - preclaim);
    int min_messages = (optimistic_needed + w - 2) / max(1, w - 1);
    int max_messages = min(preclaim - 1, (total_cells + w - 1) / w + agents * 3 + 10);
    min_messages = max(0, min(min_messages - agents - 5, max_messages));

    for (int messages = min_messages; messages <= max_messages; ++messages) {
        Schedule cur = build_schedule_for_messages(score, agents, w, total_cells, messages);
        if (cur.known_cells > best.known_cells) {
            best = std::move(cur);
        }
    }
    return best;
}

static bool is_good_score(int score, int agents, int w, int total_cells) {
    return build_best_schedule(score, agents, w, total_cells).known_cells >= total_cells;
}

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

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

    auto skip_turn = [&]() {
        cout << "." << endl;
        string reply;
        if (!(cin >> reply)) {
            exit(0);
        }
    };

    const int total = n * n;
    const int per_message = bits_per_message(max_msg_len);

    int lo = 1;
    int hi = total + 1;
    while (lo < hi) {
        int mid = (lo + hi) / 2;
        if (is_good_score(mid, num_agents, per_message, total)) {
            hi = mid;
        } else {
            lo = mid + 1;
        }
    }

    int old_agent0_queries = owned_count(total, num_agents, 0);
    int old_total_messages = 0;
    for (int id = 1; id < num_agents; ++id) {
        int cnt = owned_count(total, num_agents, id);
        old_total_messages += (cnt + per_message - 1) / per_message;
    }
    int old_score_estimate = old_agent0_queries + old_total_messages + 1;

    if (old_score_estimate <= lo) {
        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 r = idx / n + 1;
            int c = idx % n + 1;
            my_bits.push_back(query(r, c));
        }

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

        vector<vector<unsigned char>> grid(n + 1, vector<unsigned char>(n + 1, 0));
        for (int idx = 0, p = 0; idx < total; idx += num_agents, ++p) {
            int r = idx / n + 1;
            int c = idx % n + 1;
            grid[r][c] = my_bits[p];
        }

        vector<vector<string>> messages_by_agent(num_agents);
        vector<int> remaining_messages(num_agents, 0);
        int total_remaining = 0;
        for (int id = 1; id < num_agents; ++id) {
            int bit_count = owned_count(total, num_agents, id);
            remaining_messages[id] = (bit_count + per_message - 1) / per_message;
            total_remaining += remaining_messages[id];
            messages_by_agent[id].reserve(remaining_messages[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;
            }
            string sender_token = line.substr(0, sep);
            string body = line.substr(sep + 1);
            int sender = stoi(sender_token);
            if (1 <= sender && sender < num_agents && remaining_messages[sender] > 0) {
                messages_by_agent[sender].push_back(body);
                --remaining_messages[sender];
                --total_remaining;
            }
        }

        for (int id = 1; id < num_agents; ++id) {
            int bit_count = owned_count(total, num_agents, id);
            vector<unsigned char> bits;
            bits.reserve(bit_count);
            for (const string &body : messages_by_agent[id]) {
                int take = min(per_message, bit_count - (int)bits.size());
                vector<unsigned char> chunk = decode_chunk(body, take);
                bits.insert(bits.end(), chunk.begin(), chunk.end());
            }
            for (int idx = id, p = 0; idx < total; idx += num_agents, ++p) {
                int r = idx / n + 1;
                int c = idx % n + 1;
                grid[r][c] = bits[p];
            }
        }

        const int dr[4] = {-1, 0, 1, 0};
        const int dc[4] = {0, -1, 0, 1};
        const char step[4] = {'U', 'L', 'D', 'R'};

        vector<vector<int>> seen(n + 1, vector<int>(n + 1, 0));
        vector<vector<pair<int, int>>> parent(n + 1, vector<pair<int, int>>(n + 1, {-1, -1}));
        vector<vector<char>> parent_step(n + 1, vector<char>(n + 1, 0));
        queue<pair<int, int>> q;
        if (grid[1][1]) {
            seen[1][1] = 1;
            q.push({1, 1});
        }

        while (!q.empty() && !seen[n][n]) {
            auto [r, c] = q.front();
            q.pop();
            for (int d = 0; d < 4; ++d) {
                int nr = r + dr[d];
                int nc = c + dc[d];
                if (nr < 1 || nr > n || nc < 1 || nc > n || seen[nr][nc] || !grid[nr][nc]) {
                    continue;
                }
                seen[nr][nc] = 1;
                parent[nr][nc] = {r, c};
                parent_step[nr][nc] = step[d];
                q.push({nr, nc});
            }
        }

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

        string path;
        for (int r = n, c = n; !(r == 1 && c == 1);) {
            char ch = parent_step[r][c];
            path.push_back(ch);
            auto [pr, pc] = parent[r][c];
            r = pr;
            c = pc;
        }
        reverse(path.begin(), path.end());

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

    Schedule schedule = build_best_schedule(lo, num_agents, per_message, total);

    if (agent_id != 0) {
        int message_count = (int)schedule.payloads[agent_id].size();
        if (message_count == 0) {
            cout << "halt" << endl;
            return 0;
        }

        int cell_capacity = 0;
        for (int payload : schedule.payloads[agent_id]) {
            cell_capacity += payload;
        }
        int offset = schedule.cell_offset[agent_id];
        vector<unsigned char> bits(cell_capacity, 0);
        int actual = max(0, min(cell_capacity, total - offset));

        int turn = 1;
        int queried = 0;
        int sent_bits = 0;
        for (int msg = 0; msg < message_count; ++msg) {
            int send_turn = schedule.agent0_queries + schedule.send_slots[agent_id][msg];
            while (turn < send_turn) {
                if (queried < actual) {
                    int idx = offset + queried;
                    int r = idx / n + 1;
                    int c = idx % n + 1;
                    bits[queried] = query(r, c);
                    ++queried;
                } else {
                    skip_turn();
                }
                ++turn;
            }

            int payload = schedule.payloads[agent_id][msg];
            cout << "> 0 " << encode_chunk(bits, sent_bits, payload, max_msg_len) << endl;
            string reply;
            if (!(cin >> reply)) {
                return 0;
            }
            sent_bits += payload;
            ++turn;
        }
        cout << "halt" << endl;
        return 0;
    }

    vector<vector<unsigned char>> grid(n + 1, vector<unsigned char>(n + 1, 0));
    int agent0_actual = min(schedule.agent0_queries, total);
    for (int idx = 0; idx < agent0_actual; ++idx) {
        int r = idx / n + 1;
        int c = idx % n + 1;
        grid[r][c] = query(r, c);
    }

    vector<vector<string>> messages_by_agent(num_agents);
    for (int id = 1; id < num_agents; ++id) {
        messages_by_agent[id].reserve(schedule.payloads[id].size());
    }

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

    for (int id = 1; id < num_agents; ++id) {
        int offset = schedule.cell_offset[id];
        int cell_capacity = 0;
        for (int payload : schedule.payloads[id]) {
            cell_capacity += payload;
        }
        int actual = max(0, min(cell_capacity, total - offset));
        int written = 0;
        for (int msg = 0; msg < (int)messages_by_agent[id].size(); ++msg) {
            int payload = schedule.payloads[id][msg];
            vector<unsigned char> chunk = decode_chunk(messages_by_agent[id][msg], payload);
            for (int j = 0; j < payload && written < actual; ++j, ++written) {
                int idx = offset + written;
                int r = idx / n + 1;
                int c = idx % n + 1;
                grid[r][c] = chunk[j];
            }
        }
        if (written != actual) {
            cout << "halt" << endl;
            return 0;
        }
    }

    for (int idx = schedule.agent0_queries; idx < total; ++idx) {
        int owner = -1;
        for (int id = 1; id < num_agents; ++id) {
            int begin = schedule.cell_offset[id];
            int end = begin;
            for (int payload : schedule.payloads[id]) {
                end += payload;
            }
            if (begin <= idx && idx < end) {
                owner = id;
                break;
            }
        }
        if (owner == -1) {
            int r = idx / n + 1;
            int c = idx % n + 1;
            grid[r][c] = 0;
        }
    }

    const int dr[4] = {-1, 0, 1, 0};
    const int dc[4] = {0, -1, 0, 1};
    const char step[4] = {'U', 'L', 'D', 'R'};

    vector<vector<int>> seen(n + 1, vector<int>(n + 1, 0));
    vector<vector<pair<int, int>>> parent(n + 1, vector<pair<int, int>>(n + 1, {-1, -1}));
    vector<vector<char>> parent_step(n + 1, vector<char>(n + 1, 0));
    queue<pair<int, int>> q;
    if (grid[1][1]) {
        seen[1][1] = 1;
        q.push({1, 1});
    }

    while (!q.empty() && !seen[n][n]) {
        auto [r, c] = q.front();
        q.pop();
        for (int d = 0; d < 4; ++d) {
            int nr = r + dr[d];
            int nc = c + dc[d];
            if (nr < 1 || nr > n || nc < 1 || nc > n || seen[nr][nc] || !grid[nr][nc]) {
                continue;
            }
            seen[nr][nc] = 1;
            parent[nr][nc] = {r, c};
            parent_step[nr][nc] = step[d];
            q.push({nr, nc});
        }
    }

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

    string path;
    for (int r = n, c = n; !(r == 1 && c == 1);) {
        char ch = parent_step[r][c];
        path.push_back(ch);
        auto [pr, pc] = parent[r][c];
        r = pr;
        c = pc;
    }
    reverse(path.begin(), path.end());

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