// v4: full scan + tree deduction.
//
// Like v3, but exploits that the open edges form a spanning tree of the
// rooms, so ~half the edges never need a probe:
//   cycle rule : if two rooms are already connected by known-open edges,
//                the edge between them MUST be closed.
//   degree rule: every room has degree >= 1; if all other incident edges of
//                a room are known-closed and it has no open edge yet, its
//                last unknown edge MUST be open.
// Scanners own CONTIGUOUS geometric bands of a row-major edge ordering
// (locality is what makes deductions fire) and sweep them in order, probing
// only undeducible edges. The bit stream to the dispatcher is positional
// and includes deduced bits, so the protocol is unchanged from v3.
//
// Roles by AGENT_ID:
//   A == 1 : agent 0 solo-walks.   A <= 4 : independent walkers (as v3).
//   A >= 5 : 0 = dispatcher (also sweeps a half-weight band of its own
//            during idle turns when scanners are few), 1..A-1 = scanners.
// Scanner -> dispatcher: "S <k> <enc>" — bits k.. of its own band, packed
// 6 per char ('0'+v). Dispatcher runs union-find + the same deduction rules
// globally and claims as soon as start and goal connect.
#include <bits/stdc++.h>
using namespace std;

static long long N, A, ID, MAXLEN;
static int m;

static const int di[4] = {1, 0, -1, 0}; // D R U L
static const int dj[4] = {0, 1, 0, -1};
static const char dch[4] = {'D', 'R', 'U', 'L'};

static string rdline() {
    string s;
    if (!getline(cin, s)) exit(0);
    return s;
}
static void wr(const string &s) { cout << s << "\n" << flush; }

// ---- global edge order: row-major by cell row. Block i (i < m-1) holds
// m-1 horizontal edges of room-row i then m vertical edges below it; the
// last block holds only the m-1 horizontals of room-row m-1.
static long long numEdges() { return 2LL * m * (m - 1); }
struct EdgeRef { int pr, pc, ra, rb, dir; }; // probe cell, rooms, dir ra->rb
static EdgeRef edgeInfo(long long e) {
    long long block = e / (2 * m - 1), off = e % (2 * m - 1);
    int i = (int)block, j;
    EdgeRef x;
    if (off < m - 1) { // horizontal (i,j)-(i,j+1)
        j = (int)off;
        x = {2 * i + 1, 2 * j + 2, i * m + j, i * m + j + 1, 1};
    } else {           // vertical (i,j)-(i+1,j)
        j = (int)(off - (m - 1));
        x = {2 * i + 2, 2 * j + 1, i * m + j, (i + 1) * m + j, 0};
    }
    return x;
}

// ---- role/band layout (identical on every agent) ----
// Scanners weigh 2 units each; the dispatcher takes 1 unit (at the END of
// the edge list) when scanners are few, else 0.
static long long S() { return A - 1; }
static int dispW() { return S() <= 8 ? 1 : 0; }
static long long units() { return 2 * S() + dispW(); }
static void scannerBand(long long q, long long &lo, long long &hi) {
    long long E = numEdges(), U = units();
    lo = E * (2 * q) / U;
    hi = E * (2 * q + 2) / U;
}
static void dispBand(long long &lo, long long &hi) {
    long long E = numEdges(), U = units();
    lo = E * (2 * S()) / U; // zero-length when dispW()==0
    hi = E;
}

// ---- shared knowledge state + deduction rules ----
struct Know {
    vector<int> dsu;
    vector<uint8_t> knownMask, openMask; // per room, bit d = edge in dir d
    Know() : dsu(m * m), knownMask((size_t)m * m, 0), openMask((size_t)m * m, 0) {
        iota(dsu.begin(), dsu.end(), 0);
    }
    int find(int x) { while (dsu[x] != x) x = dsu[x] = dsu[dsu[x]]; return x; }
    int incident(int room) {
        int r = room / m, c = room % m, k = 0;
        for (int d = 0; d < 4; d++) {
            int nr = r + di[d], nc = c + dj[d];
            if (nr >= 0 && nc >= 0 && nr < m && nc < m) k++;
        }
        return k;
    }
    void set(int ra, int rb, int dir, bool open) { // dir: ra->rb
        knownMask[ra] |= 1 << dir;
        knownMask[rb] |= 1 << (dir ^ 2);
        if (open) {
            openMask[ra] |= 1 << dir;
            openMask[rb] |= 1 << (dir ^ 2);
            dsu[find(ra)] = find(rb);
        }
    }
    // -1 unknown, else 0/1
    int deduce(int ra, int rb, int dir) {
        if (find(ra) == find(rb)) return 0;               // cycle rule
        for (int x : {ra, rb}) {                          // degree rule
            if (openMask[x]) continue;
            if (__builtin_popcount(knownMask[x]) == incident(x) - 1) return 1;
        }
        return -1;
    }
};

// ---------------- walker (unchanged from v3) ----------------
static void walker(bool fromStart, int bias) {
    int rootR = fromStart ? 0 : m - 1, rootC = rootR;
    int tgtR = fromStart ? m - 1 : 0, tgtC = tgtR;
    const int root = rootR * m + rootC, tgt = tgtR * m + tgtC;
    vector<uint8_t> vis((size_t)m * m, 0);
    vector<int> par((size_t)m * m, -1);
    vector<uint8_t> pmv((size_t)m * m, 0);
    struct Fr { int room; uint8_t ord[4]; int k; };
    vector<Fr> st;
    auto mkFr = [&](int room) {
        Fr f; f.room = room; f.k = 0;
        int r = room / m, c = room % m;
        int sc[4] = {tgtR - r, tgtC - c, r - tgtR, c - tgtC};
        int idx[4] = {0, 1, 2, 3};
        stable_sort(idx, idx + 4, [&](int a, int b) {
            if (sc[a] != sc[b]) return sc[a] > sc[b];
            return bias ? a > b : a < b;
        });
        for (int t = 0; t < 4; t++) f.ord[t] = (uint8_t)idx[t];
        return f;
    };
    vis[root] = 1;
    st.push_back(mkFr(root));
    while (!st.empty()) {
        Fr &f = st.back();
        if (f.k == 4) { st.pop_back(); continue; }
        int d = f.ord[f.k++];
        int i = f.room / m, j = f.room % m;
        int ni = i + di[d], nj = j + dj[d];
        if (ni < 0 || nj < 0 || ni >= m || nj >= m) continue;
        int nxt = ni * m + nj;
        if (vis[nxt]) continue;
        wr("? " + to_string(2 * i + 1 + di[d]) + " " + to_string(2 * j + 1 + dj[d]));
        if (rdline()[0] != '1') continue;
        vis[nxt] = 1;
        par[nxt] = f.room;
        pmv[nxt] = (uint8_t)d;
        if (nxt == tgt) {
            vector<uint8_t> seq;
            for (int v = tgt; v != root; v = par[v]) seq.push_back(pmv[v]);
            reverse(seq.begin(), seq.end());
            string path;
            if (fromStart) {
                for (uint8_t mv : seq) { path += dch[mv]; path += dch[mv]; }
            } else {
                for (int t = (int)seq.size() - 1; t >= 0; t--) {
                    char c = dch[seq[t] ^ 2];
                    path += c; path += c;
                }
            }
            wr("! " + path);
            exit(0);
        }
        st.push_back(mkFr(nxt));
    }
    wr("halt");
    exit(1);
}
static void soloSolve() { walker(true, 0); }

// ---------------- scanner ----------------
static void scanner(long long q) {
    long long lo, hi;
    scannerBand(q, lo, hi);
    Know K;
    long long batchBits = min(120LL, (MAXLEN - 24) * 6);
    if (batchBits < 6) batchBits = 6;
    deque<uint8_t> pending; // unsent bits, in band order
    long long sent = 0;     // bits already sent (= band-sequence index of pending[0])
    auto flush = [&](long long nbits) { // send nbits pending bits; costs the turn
        string enc;
        for (long long t = 0; t < nbits; t += 6) {
            int v = 0;
            for (int b = 0; b < 6; b++)
                v = (v << 1) | (t + b < nbits ? pending[t + b] : 0);
            enc.push_back((char)('0' + v));
        }
        wr("> 0 S " + to_string(sent) + " " + enc);
        rdline(); // OK
        pending.erase(pending.begin(), pending.begin() + nbits);
        sent += nbits;
    };
    long long e = lo;
    while (e < hi || !pending.empty()) {
        // deduce everything currently free (costs no turns)
        while (e < hi) {
            EdgeRef x = edgeInfo(e);
            int v = K.deduce(x.ra, x.rb, x.dir);
            if (v < 0) break;
            K.set(x.ra, x.rb, x.dir, v);
            pending.push_back((uint8_t)v);
            e++;
        }
        if ((long long)pending.size() >= batchBits) { flush(batchBits); continue; }
        if (e >= hi) {
            if (!pending.empty()) flush((long long)pending.size());
            break;
        }
        EdgeRef x = edgeInfo(e);
        wr("? " + to_string(x.pr) + " " + to_string(x.pc));
        int bit = rdline()[0] == '1' ? 1 : 0;
        K.set(x.ra, x.rb, x.dir, bit);
        pending.push_back((uint8_t)bit);
        e++;
    }
    wr("halt");
    exit(0);
}

// ---------------- dispatcher ----------------
static void dispatcher() {
    const long long E = numEdges();
    Know K;
    vector<uint8_t> haveBit((size_t)E, 0);
    const int start = 0, goal = m * m - 1;
    long long known = 0, misses = 0;
    long long dLo, dHi;
    dispBand(dLo, dHi);
    long long dPos = dLo;
    bool lastMiss = false;

    auto record = [&](long long e, int bit) {
        if (haveBit[e]) return;
        haveBit[e] = 1;
        known++;
        EdgeRef x = edgeInfo(e);
        K.set(x.ra, x.rb, x.dir, bit);
    };
    auto tryClaim = [&]() {
        if (K.find(start) != K.find(goal)) return;
        vector<int> par((size_t)m * m, -1);
        vector<uint8_t> pmv((size_t)m * m, 0), seen((size_t)m * m, 0);
        deque<int> q{start};
        seen[start] = 1;
        while (!q.empty()) {
            int cur = q.front(); q.pop_front();
            if (cur == goal) break;
            int r = cur / m, c = cur % m;
            for (int d = 0; d < 4; d++) {
                if (!(K.openMask[cur] & (1 << d))) continue;
                int nxt = (r + di[d]) * m + (c + dj[d]);
                if (seen[nxt]) continue;
                seen[nxt] = 1;
                par[nxt] = cur;
                pmv[nxt] = (uint8_t)d;
                q.push_back(nxt);
            }
        }
        if (!seen[goal]) return;
        string path;
        vector<uint8_t> seq;
        for (int v = goal; v != start; v = par[v]) seq.push_back(pmv[v]);
        for (int t = (int)seq.size() - 1; t >= 0; t--) {
            path += dch[seq[t]]; path += dch[seq[t]];
        }
        wr("! " + path);
        exit(0);
    };

    for (;;) {
        tryClaim();
        if (known >= E || misses > 30000) soloSolve();
        // sweep own band on idle turns (deductions are free)
        while (dPos < dHi && haveBit[dPos]) dPos++;
        if (dPos < dHi) {
            EdgeRef x = edgeInfo(dPos);
            int v = K.deduce(x.ra, x.rb, x.dir);
            if (v >= 0) { record(dPos, v); dPos++; continue; } // no turn spent
            if (lastMiss) {
                wr("? " + to_string(x.pr) + " " + to_string(x.pc));
                int bit = rdline()[0] == '1' ? 1 : 0;
                record(dPos, bit);
                dPos++;
                lastMiss = false;
                continue;
            }
        }
        wr("< ?");
        string line = rdline();
        if (line == "- -") { misses++; lastMiss = true; continue; }
        lastMiss = false;
        istringstream in(line);
        long long snd, k; string tag, enc;
        in >> snd >> tag >> k >> enc;
        if (tag != "S") continue;
        long long lo, hi;
        scannerBand(snd - 1, lo, hi);
        for (size_t t = 0; t < enc.size() * 6; t++) {
            long long e = lo + k + (long long)t;
            if (e >= hi) break;
            int bit = ((enc[t / 6] - '0') >> (5 - t % 6)) & 1;
            record(e, bit);
        }
    }
}

int main() {
    {
        istringstream in(rdline());
        in >> N >> A >> ID >> MAXLEN;
    }
    m = (int)((N + 1) / 2);
    if (N == 1) {
        if (ID == 0) wr("!");
        else wr("halt");
        return 0;
    }
    if (A == 1) { walker(true, 0); return 0; }
    if (A <= 4) {
        walker(ID % 2 == 0, (int)(ID / 2));
        return 0;
    }
    if (ID == 0) dispatcher();
    else scanner(ID - 1);
    return 0;
}
