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

static int N, NUM_AGENTS, AGENT_ID, MAX_MSG_LEN;

static string ask_line(const string &cmd) {
    cout << cmd << '\n' << flush;
    string s;
    if (!getline(cin, s)) exit(0);
    return s;
}

static void send_no_reply(const string &cmd) {
    cout << cmd << '\n' << flush;
}

static long long count_for_agent(long long total, int p, int A) {
    if (p >= total) return 0;
    return (total - 1 - p) / A + 1;
}

// Packs 0/1 bytes into printable ASCII. 6 bits per char, chars 33..96.
static string pack_bits(const vector<unsigned char> &bits) {
    string out;
    out.reserve((bits.size() + 5) / 6);
    for (size_t i = 0; i < bits.size(); i += 6) {
        int v = 0;
        for (int b = 0; b < 6 && i + b < bits.size(); ++b) {
            if (bits[i + b]) v |= (1 << b);
        }
        out.push_back(char(33 + v));
    }
    return out;
}

static void place_unpacked(vector<unsigned char> &grid, int p, const string &packed, long long need_bits) {
    long long k = 0;
    long long total = 1LL * N * N;
    for (char ch : packed) {
        int v = int((unsigned char)ch) - 33;
        if (v < 0 || v >= 64) continue; // Should never happen for our messages.
        for (int b = 0; b < 6 && k < need_bits; ++b) {
            long long idx = p + k * 1LL * NUM_AGENTS;
            if (0 <= idx && idx < total) grid[(size_t)idx] = (unsigned char)((v >> b) & 1);
            ++k;
        }
        if (k >= need_bits) break;
    }
}

static string shortest_path_in_known_tree(const vector<unsigned char> &empty) {
    const int total = N * N;
    if (N == 1) return "";

    vector<int> parent(total, -2);
    vector<char> parent_dir(total, 0);
    queue<int> q;
    parent[0] = -1;
    q.push(0);

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

    while (!q.empty()) {
        int v = q.front();
        q.pop();
        if (v == total - 1) break;
        int r = v / N;
        int c = v % N;
        for (int z = 0; z < 4; ++z) {
            int nr = r + dr[z], nc = c + dc[z];
            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;
            int to = nr * N + nc;
            if (!empty[(size_t)to] || parent[to] != -2) continue;
            parent[to] = v;
            parent_dir[to] = dir[z];
            q.push(to);
        }
    }

    string path;
    int cur = total - 1;
    // The statement guarantees reachability, but avoid undefined behavior on malformed input/referee.
    if (parent[cur] == -2) return path;
    while (cur != 0) {
        path.push_back(parent_dir[cur]);
        cur = parent[cur];
    }
    reverse(path.begin(), path.end());
    return path;
}

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

    if (!(cin >> N >> NUM_AGENTS >> AGENT_ID >> MAX_MSG_LEN)) return 0;
    string dummy;
    getline(cin, dummy); // consume the rest of the startup line

    if (N == 1) {
        if (AGENT_ID == 0) send_no_reply("!");
        else send_no_reply("halt");
        return 0;
    }

    const long long total = 1LL * N * N;
    const long long my_count = count_for_agent(total, AGENT_ID, NUM_AGENTS);

    vector<unsigned char> my_bits;
    my_bits.reserve((size_t)my_count);

    // Phase 1: every agent queries cells with linear index idx % NUM_AGENTS == AGENT_ID.
    for (long long idx = AGENT_ID; idx < total; idx += NUM_AGENTS) {
        int r = int(idx / N) + 1;
        int c = int(idx % N) + 1;
        string reply = ask_line("? " + to_string(r) + " " + to_string(c));
        my_bits.push_back((!reply.empty() && reply[0] == '1') ? 1 : 0);
    }

    string my_packed = pack_bits(my_bits);
    int chunk_len = max(1, MAX_MSG_LEN);

    if (AGENT_ID != 0) {
        // Phase 2 for workers: stream our packed scan to agent 0, then leave.
        for (size_t pos = 0; pos < my_packed.size(); pos += (size_t)chunk_len) {
            string body = my_packed.substr(pos, (size_t)chunk_len);
            (void)ask_line("> 0 " + body); // reply is OK
        }
        send_no_reply("halt");
        return 0;
    }

    // Agent 0 collects all packed scans. Messages may already be queued while it was querying.
    vector<string> packed(NUM_AGENTS);
    packed[0] = my_packed;
    vector<long long> need_bits(NUM_AGENTS), need_chars(NUM_AGENTS);
    for (int p = 0; p < NUM_AGENTS; ++p) {
        need_bits[p] = count_for_agent(total, p, NUM_AGENTS);
        need_chars[p] = (need_bits[p] + 5) / 6;
    }

    long long missing = 0;
    for (int p = 1; p < NUM_AGENTS; ++p) missing += need_chars[p];

    while (missing > 0) {
        string reply = ask_line("< ?");
        if (reply == "- -") continue;
        size_t sp = reply.find(' ');
        if (sp == string::npos) continue;
        int sender = -1;
        try {
            sender = stoi(reply.substr(0, sp));
        } catch (...) {
            continue;
        }
        if (sender <= 0 || sender >= NUM_AGENTS) continue;
        string body = reply.substr(sp + 1);
        long long before = (long long)packed[sender].size();
        if (before >= need_chars[sender]) continue;
        long long take = min<long long>((long long)body.size(), need_chars[sender] - before);
        packed[sender].append(body.data(), (size_t)take);
        missing -= take;
    }

    vector<unsigned char> grid((size_t)total, 0);
    for (int p = 0; p < NUM_AGENTS; ++p) {
        place_unpacked(grid, p, packed[p], need_bits[p]);
    }

    string path = shortest_path_in_known_tree(grid);
    send_no_reply("! " + path);
    return 0;
}
