#pragma GCC optimize("Ofast,unroll-loops,omit-frame-pointer")
#include <bits/stdc++.h>
using namespace std;

struct Edge {
    int r, c;
    int u, v;
};

static string encode_bits(const vector<unsigned char>& bits, int l, int r) {
    string s;
    for (int i = l; i < r; i += 6) {
        int x = 0;
        for (int b = 0; b < 6 && i + b < r; ++b) x |= (int(bits[i + b]) << b);
        s.push_back(char(63 + x)); // printable ASCII, 63..126
    }
    return s;
}

static void decode_bits(const string& s, int need, vector<unsigned char>& out) {
    out.clear();
    out.reserve(need);
    for (char ch : s) {
        int x = int(ch) - 63;
        if (x < 0) x = 0;
        for (int b = 0; b < 6 && (int)out.size() < need; ++b) out.push_back((x >> b) & 1);
    }
    while ((int)out.size() < need) out.push_back(0);
}

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

static string read_line() {
    string s;
    if (!getline(cin, s)) exit(0);
    return s;
}

int main(int argc, char** argv) {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    unsigned long long seed = 0;
    if (argc > 1) seed = strtoull(argv[1], nullptr, 10);
    (void)seed;

    int N, A, id, maxLen;
    if (!(cin >> N >> A >> id >> maxLen)) return 0;
    string dummy;
    getline(cin, dummy);

    int m = (N + 1) / 2;
    vector<Edge> edges;
    edges.reserve(2 * m * max(0, m - 1));
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < m; ++j) {
            int u = i * m + j;
            int rr = 2 * i + 1, cc = 2 * j + 1;
            if (i + 1 < m) {
                int v = (i + 1) * m + j;
                edges.push_back({rr + 1, cc, u, v});
            }
            if (j + 1 < m) {
                int v = i * m + (j + 1);
                edges.push_back({rr, cc + 1, u, v});
            }
        }
    }

    int E = (int)edges.size();
    vector<int> mine;
    mine.reserve((E + A - 1) / A + 1);
    for (int e = id; e < E; e += A) mine.push_back(e);

    vector<unsigned char> myBits;
    myBits.reserve(mine.size());
    for (int e : mine) {
        send_line("? " + to_string(edges[e].r) + " " + to_string(edges[e].c));
        string ans = read_line();
        myBits.push_back(!ans.empty() && ans[0] == '1');
    }

    int payloadLen = max(1, maxLen);
    int bitsPerMsg = max(1, payloadLen * 6);
    int myChunks = ((int)myBits.size() + bitsPerMsg - 1) / bitsPerMsg;

    if (id != 0) {
        for (int ch = 0; ch < myChunks; ++ch) {
            int l = ch * bitsPerMsg;
            int r = min<int>(myBits.size(), l + bitsPerMsg);
            string body = encode_bits(myBits, l, r);
            send_line("> 0 " + body);
            (void)read_line();
        }
        send_line("halt");
        return 0;
    }

    vector<unsigned char> all(E, 0), tmp;
    for (int k = 0; k < (int)mine.size(); ++k) all[mine[k]] = myBits[k];

    vector<int> chunksExpected(A, 0), chunksGot(A, 0);
    int totalExpected = 0, totalGot = 0;
    for (int a = 1; a < A; ++a) {
        int cnt = 0;
        for (int e = a; e < E; e += A) ++cnt;
        chunksExpected[a] = (cnt + bitsPerMsg - 1) / bitsPerMsg;
        totalExpected += chunksExpected[a];
    }

    while (totalGot < totalExpected) {
        send_line("< ?");
        string resp = read_line();
        if (resp == "- -") continue;
        size_t sp = resp.find(' ');
        if (sp == string::npos) continue;
        int sender = stoi(resp.substr(0, sp));
        string body = resp.substr(sp + 1);
        if (sender <= 0 || sender >= A) continue;
        int ch = chunksGot[sender]++;
        ++totalGot;

        int totalBitsSender = 0;
        for (int e = sender; e < E; e += A) ++totalBitsSender;
        int l = ch * bitsPerMsg;
        int need = min(bitsPerMsg, max(0, totalBitsSender - l));
        decode_bits(body, need, tmp);
        for (int k = 0; k < need; ++k) {
            int edgeIdx = sender + (l + k) * A;
            if (edgeIdx < E) all[edgeIdx] = tmp[k];
        }
    }

    vector<vector<pair<int, char>>> g(m * m);
    for (int e = 0; e < E; ++e) {
        if (!all[e]) continue;
        int u = edges[e].u, v = edges[e].v;
        int ur = u / m, uc = u % m;
        int vr = v / m, vc = v % m;
        char uv, vu;
        if (vr == ur + 1) { uv = 'D'; vu = 'U'; }
        else if (vr == ur - 1) { uv = 'U'; vu = 'D'; }
        else if (vc == uc + 1) { uv = 'R'; vu = 'L'; }
        else { uv = 'L'; vu = 'R'; }
        g[u].push_back({v, uv});
        g[v].push_back({u, vu});
    }

    int S = 0, T = m * m - 1;
    vector<int> par(m * m, -2);
    vector<char> pmove(m * m, 0);
    queue<int> q;
    par[S] = -1;
    q.push(S);
    while (!q.empty()) {
        int u = q.front(); q.pop();
        if (u == T) break;
        for (auto [v, mv] : g[u]) {
            if (par[v] != -2) continue;
            par[v] = u;
            pmove[v] = mv;
            q.push(v);
        }
    }

    string roomMoves;
    for (int cur = T; cur != S && cur >= 0 && par[cur] >= 0; cur = par[cur]) {
        roomMoves.push_back(pmove[cur]);
    }
    reverse(roomMoves.begin(), roomMoves.end());

    string path;
    path.reserve(roomMoves.size() * 2);
    for (char mv : roomMoves) {
        path.push_back(mv);
        path.push_back(mv);
    }
    send_line("! " + path);
    return 0;
}
