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

struct Edge {
    int a, b;
    int r, c;
    char move_ab;
};

static const int BASE = 94;
static const int CHUNK_BITS = 1612;

static vector<Edge> build_edges(int n) {
    int m = (n + 1) / 2;
    vector<Edge> edges;
    edges.reserve(2 * m * max(0, m - 1));
    auto id = [m](int i, int j) { return i * m + j; };
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < m; ++j) {
            int u = id(i, j);
            if (j + 1 < m) {
                edges.push_back({u, id(i, j + 1), 2 * i + 1, 2 * j + 2, 'R'});
            }
            if (i + 1 < m) {
                edges.push_back({u, id(i + 1, j), 2 * i + 2, 2 * j + 1, 'D'});
            }
        }
    }
    return edges;
}

static string encode_bits(const vector<int>& bits) {
    string out;
    for (int i = 0; i < (int)bits.size(); i += 13) {
        int v = 0;
        for (int k = 0; k < 13; ++k) {
            if (i + k < (int)bits.size() && bits[i + k]) v |= (1 << k);
        }
        out.push_back(char('!' + (v % BASE)));
        out.push_back(char('!' + (v / BASE)));
    }
    return out;
}

static void decode_bits(const string& encoded, int count, vector<int>& out) {
    out.clear();
    out.reserve(count);
    for (int i = 0; i + 1 < (int)encoded.size(); i += 2) {
        int lo = encoded[i] - '!';
        int hi = encoded[i + 1] - '!';
        if (lo < 0 || lo >= BASE || hi < 0 || hi >= BASE) continue;
        int v = lo + BASE * hi;
        for (int k = 0; k < 13 && (int)out.size() < count; ++k) {
            out.push_back((v >> k) & 1);
        }
    }
}

static string ask_cell(int r, int c) {
    cout << "? " << r << ' ' << c << '\n' << flush;
    string reply;
    if (!(cin >> reply)) exit(0);
    return reply;
}

static void send_message(int target, const string& body) {
    cout << "> " << target << ' ' << body << '\n' << flush;
    string ok;
    if (!(cin >> ok)) exit(0);
}

static int message_count_for_worker(int q) {
    if (q == 0) return 1;
    return (q + CHUNK_BITS - 1) / CHUNK_BITS;
}

static int worker_capacity_for_turns(int turns, int total_edges) {
    int lo = 0, hi = total_edges;
    while (lo < hi) {
        int mid = (lo + hi + 1) / 2;
        if (mid + message_count_for_worker(mid) <= turns) {
            lo = mid;
        } else {
            hi = mid - 1;
        }
    }
    return lo;
}

static vector<int> compute_quotas(int total_edges, int num_agents) {
    vector<int> quotas(num_agents, 0);
    if (num_agents == 1) {
        quotas[0] = total_edges;
        return quotas;
    }

    auto feasible = [&](int turns, vector<int>* out) {
        vector<int> q(num_agents, 0);
        int remaining = total_edges;
        int qmax = worker_capacity_for_turns(turns, total_edges);
        int messages = 0;
        for (int id = 1; id < num_agents; ++id) {
            q[id] = min(qmax, remaining);
            remaining -= q[id];
            messages += message_count_for_worker(q[id]);
        }
        q[0] = remaining;
        bool ok = q[0] + messages <= turns;
        if (ok && out) *out = q;
        return ok;
    };

    int lo = 1, hi = total_edges + num_agents + 10;
    while (lo < hi) {
        int mid = (lo + hi) / 2;
        if (feasible(mid, nullptr)) hi = mid;
        else lo = mid + 1;
    }
    feasible(lo, &quotas);
    return quotas;
}

static vector<int> quota_starts(const vector<int>& quotas) {
    vector<int> starts(quotas.size() + 1, 0);
    for (int i = 0; i < (int)quotas.size(); ++i) {
        starts[i + 1] = starts[i] + quotas[i];
    }
    return starts;
}

static void receive_any(int& sender, string& body) {
    cout << "< ?" << '\n' << flush;
    string line;
    getline(cin, line);
    if (line.empty()) getline(cin, line);
    if (line == "- -") {
        sender = -1;
        body.clear();
        return;
    }
    size_t sp = line.find(' ');
    if (sp == string::npos) {
        sender = -1;
        body.clear();
        return;
    }
    sender = stoi(line.substr(0, sp));
    body = line.substr(sp + 1);
}

static void query_partition(
    const vector<Edge>& edges,
    int start,
    int end,
    vector<signed char>* master_open
) {
    vector<int> chunk;
    chunk.reserve(CHUNK_BITS);
    auto flush_chunk = [&](bool final_chunk) {
        if (chunk.empty() && !final_chunk) return;
        char kind = final_chunk ? 'F' : 'B';
        string body = string(1, kind) + " " + to_string((int)chunk.size());
        if (!chunk.empty()) body += " " + encode_bits(chunk);
        send_message(0, body);
        chunk.clear();
    };

    for (int e = start; e < end; ++e) {
        if (master_open && (*master_open)[e] != -1) continue;
        int bit = ask_cell(edges[e].r, edges[e].c) == "1";
        if (master_open) {
            (*master_open)[e] = (signed char)bit;
        } else {
            chunk.push_back(bit);
            if ((int)chunk.size() >= CHUNK_BITS) flush_chunk(false);
        }
    }
    if (!master_open) {
        flush_chunk(true);
        cout << "halt" << '\n' << flush;
        exit(0);
    }
}

static string build_path(int n, const vector<Edge>& edges, const vector<signed char>& open) {
    int m = (n + 1) / 2;
    int rooms = m * m;
    vector<vector<pair<int, char>>> g(rooms);
    for (int i = 0; i < (int)edges.size(); ++i) {
        if (open[i] != 1) continue;
        const Edge& e = edges[i];
        g[e.a].push_back({e.b, e.move_ab});
        char back = (e.move_ab == 'R') ? 'L' : 'U';
        g[e.b].push_back({e.a, back});
    }

    vector<int> parent(rooms, -1);
    vector<char> parent_move(rooms, 0);
    queue<int> q;
    parent[0] = 0;
    q.push(0);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        if (u == rooms - 1) break;
        for (auto [v, mv] : g[u]) {
            if (parent[v] != -1) continue;
            parent[v] = u;
            parent_move[v] = mv;
            q.push(v);
        }
    }

    if (parent[rooms - 1] == -1) {
        // Should never happen after all edge cells are known. Prefer a no-claim
        // timeout over an invalid claim if something goes badly wrong.
        while (true) {
            cout << "." << '\n' << flush;
            string ok;
            if (!(cin >> ok)) exit(0);
        }
    }

    vector<char> room_moves;
    for (int v = rooms - 1; v != 0; v = parent[v]) {
        room_moves.push_back(parent_move[v]);
    }
    reverse(room_moves.begin(), room_moves.end());

    string path;
    path.reserve(room_moves.size() * 2);
    for (char mv : room_moves) {
        path.push_back(mv);
        path.push_back(mv);
    }
    return path;
}

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 << "!" << '\n' << flush;
        } else {
            cout << "halt" << '\n' << flush;
        }
        return 0;
    }

    vector<Edge> edges = build_edges(n);
    vector<int> quotas = compute_quotas((int)edges.size(), num_agents);
    vector<int> starts = quota_starts(quotas);

    if (agent_id != 0) {
        query_partition(edges, starts[agent_id], starts[agent_id + 1], nullptr);
        return 0;
    }

    vector<signed char> open(edges.size(), -1);
    query_partition(edges, starts[0], starts[1], &open);

    vector<int> next_edge(num_agents);
    for (int id = 1; id < num_agents; ++id) next_edge[id] = starts[id];

    int done = 0;
    vector<int> bits;
    while (done < num_agents - 1) {
        int sender;
        string body;
        receive_any(sender, body);
        if (sender <= 0 || sender >= num_agents) continue;
        if (body.rfind("B ", 0) == 0 || body.rfind("F ", 0) == 0) {
            bool final_chunk = body[0] == 'F';
            size_t p = body.find(' ', 2);
            int count = 0;
            string encoded;
            if (p == string::npos) {
                count = stoi(body.substr(2));
            } else {
                count = stoi(body.substr(2, p - 2));
                encoded = body.substr(p + 1);
            }
            decode_bits(encoded, count, bits);
            for (int bit : bits) {
                int e = next_edge[sender];
                if (e >= starts[sender + 1]) break;
                open[e] = (signed char)bit;
                next_edge[sender] = e + 1;
            }
            if (final_chunk) ++done;
        }
    }

    string path = build_path(n, edges, open);
    cout << "! " << path << '\n' << flush;
    return 0;
}
