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

int N, NUM_AGENTS, AGENT_ID, MAX_MSG_LEN;
int K;
long long TOTAL_EDGES;

const string ALPHABET =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

struct EdgeInfo {
    int u;
    int v;
    char dir;
    int qr;
    int qc;
};

string read_line_or_exit() {
    string line;
    if (!getline(cin, line)) exit(0);
    return line;
}

bool ask_empty(int r, int c) {
    cout << "? " << r << ' ' << c << '\n' << flush;
    string line = read_line_or_exit();
    return !line.empty() && line[0] == '1';
}

void send_to_zero(const string& body) {
    cout << "> 0 " << body << '\n' << flush;
    (void)read_line_or_exit();
}

pair<int, string> receive_any() {
    cout << "< ?\n" << flush;
    string line = read_line_or_exit();
    if (line == "- -") return {-1, ""};

    size_t sp = line.find(' ');
    if (sp == string::npos) return {-1, ""};

    int sender = -1;
    try {
        sender = stoi(line.substr(0, sp));
    } catch (...) {
        return {-1, ""};
    }
    return {sender, line.substr(sp + 1)};
}

long long assigned_count(int id) {
    if (id < 0 || id >= NUM_AGENTS || id >= TOTAL_EDGES) return 0;
    return 1 + (TOTAL_EDGES - 1 - id) / NUM_AGENTS;
}

EdgeInfo edge_info(long long idx) {
    long long horizontal = 1LL * K * (K - 1);

    if (idx < horizontal) {
        int rr = (int)(idx / (K - 1));
        int cc = (int)(idx % (K - 1));
        int u = rr * K + cc;
        int v = rr * K + cc + 1;
        return {u, v, 'R', 2 * rr + 1, 2 * cc + 2};
    }

    idx -= horizontal;
    int rr = (int)(idx / K);
    int cc = (int)(idx % K);
    int u = rr * K + cc;
    int v = (rr + 1) * K + cc;
    return {u, v, 'D', 2 * rr + 2, 2 * cc + 1};
}

string query_my_edges_packed() {
    string packed;
    int acc = 0;
    int bit = 0;

    for (long long idx = AGENT_ID; idx < TOTAL_EDGES; idx += NUM_AGENTS) {
        EdgeInfo e = edge_info(idx);
        if (ask_empty(e.qr, e.qc)) acc |= (1 << bit);

        ++bit;
        if (bit == 6) {
            packed.push_back(ALPHABET[acc]);
            acc = 0;
            bit = 0;
        }
    }

    if (bit > 0) packed.push_back(ALPHABET[acc]);
    return packed;
}

void worker() {
    string packed = query_my_edges_packed();
    int chunk = max(1, MAX_MSG_LEN);

    for (int pos = 0; pos < (int)packed.size(); pos += chunk) {
        send_to_zero(packed.substr(pos, min(chunk, (int)packed.size() - pos)));
    }

    cout << "halt\n" << flush;
}

void add_edge(vector<vector<pair<int, char>>>& graph, int u, int v, char dir) {
    char rev = '?';
    if (dir == 'R') rev = 'L';
    if (dir == 'L') rev = 'R';
    if (dir == 'D') rev = 'U';
    if (dir == 'U') rev = 'D';

    graph[u].push_back({v, dir});
    graph[v].push_back({u, rev});
}

bool apply_packed_bits(int sender, const string& packed,
                       vector<vector<pair<int, char>>>& graph) {
    static int value[256];
    static bool initialized = false;
    if (!initialized) {
        fill(begin(value), end(value), -1);
        for (int i = 0; i < (int)ALPHABET.size(); ++i) {
            value[(unsigned char)ALPHABET[i]] = i;
        }
        initialized = true;
    }

    long long limit = assigned_count(sender);
    long long seen = 0;
    long long idx = sender;

    for (unsigned char ch : packed) {
        int val = value[ch];
        if (val < 0) return false;

        for (int b = 0; b < 6 && seen < limit; ++b, ++seen, idx += NUM_AGENTS) {
            if (val & (1 << b)) {
                EdgeInfo e = edge_info(idx);
                add_edge(graph, e.u, e.v, e.dir);
            }
        }
    }

    return seen == limit;
}

string build_room_path(const vector<vector<pair<int, char>>>& graph) {
    int rooms = K * K;
    int target = rooms - 1;

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

    while (!q.empty()) {
        int u = q.front();
        q.pop();
        if (u == target) break;

        for (auto [v, dir] : graph[u]) {
            if (parent[v] != -1) continue;
            parent[v] = u;
            parent_dir[v] = dir;
            q.push(v);
        }
    }

    if (parent[target] == -1) return "";

    string room_dirs;
    for (int cur = target; cur != 0; cur = parent[cur]) {
        room_dirs.push_back(parent_dir[cur]);
    }
    reverse(room_dirs.begin(), room_dirs.end());

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

string generic_fallback_path() {
    int total = N * N;
    vector<signed char> state(total, -1);
    vector<int> parent(total, -1);
    vector<char> parent_dir(total, 0);
    queue<int> q;

    auto id = [](int r, int c) {
        return (r - 1) * N + (c - 1);
    };

    state[0] = 1;
    parent[0] = 0;
    q.push(0);

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

    while (!q.empty() && parent[target] == -1) {
        int cur = q.front();
        q.pop();
        int r = cur / N + 1;
        int c = cur % N + 1;

        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) continue;

            int nid = id(nr, nc);
            if (state[nid] != -1) continue;

            bool empty = ask_empty(nr, nc);
            state[nid] = empty ? 1 : 0;
            if (!empty) continue;

            parent[nid] = cur;
            parent_dir[nid] = dirs[d];
            q.push(nid);
            if (nid == target) break;
        }
    }

    if (parent[target] == -1) return "";

    string path;
    for (int cur = target; cur != 0; cur = parent[cur]) {
        path.push_back(parent_dir[cur]);
    }
    reverse(path.begin(), path.end());
    return path;
}

void coordinator() {
    vector<vector<pair<int, char>>> graph(K * K);

    string mine = query_my_edges_packed();
    if (!apply_packed_bits(0, mine, graph)) {
        string path = generic_fallback_path();
        cout << "! " << path << '\n' << flush;
        return;
    }

    vector<string> received(NUM_AGENTS);
    vector<int> expected(NUM_AGENTS, 0);
    int remaining = 0;

    for (int id = 1; id < NUM_AGENTS; ++id) {
        expected[id] = (int)((assigned_count(id) + 5) / 6);
        if (expected[id] > 0) ++remaining;
    }

    while (remaining > 0) {
        auto [sender, body] = receive_any();
        if (sender <= 0 || sender >= NUM_AGENTS) continue;

        int before = (int)received[sender].size();
        if (before >= expected[sender]) continue;

        int take = min((int)body.size(), expected[sender] - before);
        received[sender].append(body.data(), take);

        if ((int)received[sender].size() == expected[sender]) {
            --remaining;
        }
    }

    bool ok = true;
    for (int id = 1; id < NUM_AGENTS; ++id) {
        if (expected[id] == 0) continue;
        ok &= apply_packed_bits(id, received[id], graph);
    }

    string path = ok ? build_room_path(graph) : "";
    if (path.empty() && N > 1) path = generic_fallback_path();

    cout << "! " << path << '\n' << flush;
}

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

    string first;
    if (!getline(cin, first)) return 0;
    {
        istringstream in(first);
        in >> N >> NUM_AGENTS >> AGENT_ID >> MAX_MSG_LEN;
    }

    if (N == 1) {
        if (AGENT_ID == 0) {
            cout << "! \n" << flush;
        } else {
            cout << "halt\n" << flush;
        }
        return 0;
    }

    K = (N + 1) / 2;
    TOTAL_EDGES = 2LL * K * (K - 1);

    if (AGENT_ID == 0) {
        coordinator();
    } else {
        worker();
    }

    return 0;
}
