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

static inline string readLine() {
    string s;
    if (!std::getline(cin, s)) { return string(); }
    while (!s.empty() && (s.back()=='\n'||s.back()=='\r')) s.pop_back();
    return s;
}
static inline void sendLine(const string& s){ cout<<s<<'\n'; cout.flush(); }

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

int main(){
    long long N,NUM_AGENTS,AGENT_ID,MAX_MSG_LEN;
    { string line=readLine(); std::istringstream iss(line); iss>>N>>NUM_AGENTS>>AGENT_ID>>MAX_MSG_LEN; }
    long long m=(N+1)/2;

    vector<Edge> edges; edges.reserve((size_t)max<long long>(0,2*m*(m-1)));
    vector<int> ER, ED; // ER[u]=edge idx of right edge (u,u+1); ED[u]=down edge (u,u+m); -1 if none
    if(m>=1){ ER.assign((size_t)(m*m),-1); ED.assign((size_t)(m*m),-1); }
    for(long long i=0;i<m;++i)for(long long j=0;j<m;++j){ int a=(int)(i*m+j);
        if(j+1<m){ ER[(size_t)a]=(int)edges.size(); edges.push_back(Edge{(int)(2*i+1),(int)(2*j+2),a,(int)(i*m+(j+1))}); }
        if(i+1<m){ ED[(size_t)a]=(int)edges.size(); edges.push_back(Edge{(int)(2*i+2),(int)(2*j+1),a,(int)((i+1)*m+j)}); } }
    long long E=(long long)edges.size();

    long long headerReserve=24; long long chunkChars=MAX_MSG_LEN-headerReserve; if(chunkChars<1)chunkChars=1;
    long long chunkBitsCap=chunkChars*6;

    if(m<=1||E==0){ if(AGENT_ID==0) sendLine("! "); else sendLine("halt"); return 0; }

    // Knobs (env, for experimentation)
    auto envll=[&](const char*k,long long def)->long long{ const char*v=getenv(k); return v?atoll(v):def; };
    // MODE: 0 auto, 1 unified(all query), 2 coordinator(agent0 pure reader)
    long long MODE = envll("MODE",0);
    long long UNI_THRESH = envll("UNI_THRESH",12); // na < thresh => unified
    long long FULL_THRESH = envll("FULL_THRESH",0); // na <= this => plain full-map (0 disables)

    // MODE5 (independent adaptive hybrid) is a measured win only at very small na:
    //   na<=3 across all N (E[1/r]~1.4-1.55), and na==4 only for N<=250 (median win there;
    //   at larger N na==4 is a median loss). Env HYB_THRESH overrides with a plain na<=cap rule.
    const char* hs=getenv("HYB_THRESH");
    if(MODE==0){
        long long thresh = 8 + N/40; if(thresh<4)thresh=4;
        const char* ut=getenv("UNI_THRESH"); if(ut) thresh=atoll(ut);
        bool useHyb;
        if(hs) useHyb = (NUM_AGENTS<=atoll(hs));
        else   useHyb = (NUM_AGENTS<=3) || (NUM_AGENTS==4 && N<=250);
        if(useHyb) MODE = 5;
        else MODE = (NUM_AGENTS < thresh) ? 1 : 2;
    }
    (void)UNI_THRESH;
    if(FULL_THRESH>0 && NUM_AGENTS<=FULL_THRESH) MODE=3;
    long long GREEDY_THRESH = envll("GREEDY_THRESH",0); // na<=this => MODE4 greedy(agent0 alone)
    if(GREEDY_THRESH>0 && NUM_AGENTS<=GREEDY_THRESH) MODE=4;

    // ---------- MODE 4: single-agent adaptive A* (agent 0 explores alone) ----------
    if(MODE==4){
        if(AGENT_ID!=0){ sendLine("halt"); return 0; }
        long long total=m*m; int START=0,GOAL=(int)(total-1);
        // adjacency discovered; explore rooms best-first by Manhattan dist to goal
        vector<vector<int>> adj((size_t)total);
        vector<char> visited((size_t)total,0);
        // queried edges dedup: store per room a bitmask of which of 4 dirs queried is complex; use set of edge order idx.
        // Represent edge by (min room, dir): we query wall cell. Track visited rooms; from a room query each not-yet-known neighbor.
        vector<char> qright((size_t)total,0), qdown((size_t)total,0); // queried edge to right / down neighbor (canonical from smaller id)
        auto gi=[&](int r){return r/(int)m;}; auto gj=[&](int r){return r%(int)m;};
        auto manh=[&](int r){ int i=gi(r),j=gj(r); int ti=(int)m-1,tj=(int)m-1; return (ti-i)+(tj-j); };
        // min-heap by manhattan
        priority_queue<pair<int,int>,vector<pair<int,int>>,greater<>> pq;
        vector<int> par((size_t)total,-2);
        visited[(size_t)START]=1; par[(size_t)START]=-1; pq.push({manh(START),START});
        auto queryEdge=[&](int r,int c)->int{ sendLine("? "+to_string(r)+" "+to_string(c)); string rep=readLine(); return (!rep.empty()&&rep[0]=='1')?1:0; };
        bool found=false;
        while(!pq.empty()){ int u=pq.top().second; pq.pop(); if(u==GOAL){found=true;break;} int i=gi(u),j=gj(u);
            // 4 neighbors; edge canonical stored on smaller-id endpoint
            // right neighbor (i,j+1)
            if(j+1<(int)m){ int v=u+1; if(!qright[(size_t)u]){ qright[(size_t)u]=1; if(queryEdge(2*i+1,2*j+2)){ if(!visited[(size_t)v]){visited[(size_t)v]=1;par[(size_t)v]=u;pq.push({manh(v),v});} } } }
            // left neighbor (i,j-1): edge stored on (i,j-1) as its right
            if(j-1>=0){ int v=u-1; if(!qright[(size_t)v]){ qright[(size_t)v]=1; if(queryEdge(2*i+1,2*j)){ if(!visited[(size_t)v]){visited[(size_t)v]=1;par[(size_t)v]=u;pq.push({manh(v),v});} } } }
            // down neighbor (i+1,j)
            if(i+1<(int)m){ int v=u+(int)m; if(!qdown[(size_t)u]){ qdown[(size_t)u]=1; if(queryEdge(2*i+2,2*j+1)){ if(!visited[(size_t)v]){visited[(size_t)v]=1;par[(size_t)v]=u;pq.push({manh(v),v});} } } }
            // up neighbor (i-1,j): edge stored on (i-1,j) as its down
            if(i-1>=0){ int v=u-(int)m; if(!qdown[(size_t)v]){ qdown[(size_t)v]=1; if(queryEdge(2*i,2*j+1)){ if(!visited[(size_t)v]){visited[(size_t)v]=1;par[(size_t)v]=u;pq.push({manh(v),v});} } } }
        }
        (void)found;
        vector<int> pr; for(int c=GOAL;c!=-1;c=par[(size_t)c]){pr.push_back(c); if(c==START)break;} reverse(pr.begin(),pr.end());
        string mv; for(size_t i=1;i<pr.size();++i){int d=pr[i]-pr[i-1]; if(d==1)mv+="RR";else if(d==-1)mv+="LL";else if(d==(int)m)mv+="DD";else if(d==-(int)m)mv+="UU";}
        sendLine("! "+mv); return 0;
    }

    // Build diagonal priority order (all agents identical) for MODE 1/2/5.
    vector<int> order;
    if(MODE==1||MODE==2||MODE==5){
        order.resize((size_t)E); for(long long e=0;e<E;++e) order[(size_t)e]=(int)e;
        long long cctr=2*(m-1);
        auto key=[&](int e)->long long{ const Edge&ed=edges[(size_t)e];
            int ai=ed.a/(int)m,aj=ed.a%(int)m,bi=ed.b/(int)m,bj=ed.b%(int)m;
            long long mi2=ai+bi,mj2=aj+bj; long long d=llabs(mi2-mj2); long long al=llabs(mi2+mj2-cctr);
            return d*4000000LL+al*2000LL+e; };
        sort(order.begin(),order.end(),[&](int x,int y){return key(x)<key(y);});
    }

    // ---------- MODE 5: independent adaptive hybrid (very small na) ----------
    // Each agent grows its OWN reachable component from a diagonal seed via best-first-toward-goal
    // (self-latency 0), falling back to the private strided diagonal order when its frontier has
    // no unqueried edge. Only communication is worker->agent0 pushes of discovered OPEN edge
    // indices; agent0 unions them (+ its own discoveries) and claims when START-GOAL connect.
    if(MODE==5){
        long long total=m*m; int START=0, GOAL=(int)(total-1);
        auto gi=[&](int r){return r/(int)m;}; auto gj=[&](int r){return r%(int)m;};
        vector<char> qd((size_t)E,0);
        vector<char> visited((size_t)total,0);
        priority_queue<pair<int,int>> pq;   // max-heap by (i+j): explore toward goal
        int seed; { double frac=(2.0*AGENT_ID+1.0)/(2.0*NUM_AGENTS); int d=(int)llround(frac*(m-1)); seed=d*(int)m+d; }
        if(AGENT_ID==0) seed=START;
        if(AGENT_ID==NUM_AGENTS-1) seed=GOAL;
        visited[(size_t)seed]=1; pq.push({gi(seed)+gj(seed),seed});
        long long fptr=AGENT_ID;
        auto incidentBest=[&](int u,int&eidx,int&to)->bool{
            int bi=-1,bt=-1,bk=-1; int i=gi(u),j=gj(u);
            if(j+1<(int)m){int e=ER[(size_t)u]; if(e>=0&&!qd[(size_t)e]){int v=u+1,k=gi(v)+gj(v); if(k>bk){bk=k;bi=e;bt=v;}}}
            if(j-1>=0){int e=ER[(size_t)(u-1)]; if(e>=0&&!qd[(size_t)e]){int v=u-1,k=gi(v)+gj(v); if(k>bk){bk=k;bi=e;bt=v;}}}
            if(i+1<(int)m){int e=ED[(size_t)u]; if(e>=0&&!qd[(size_t)e]){int v=u+(int)m,k=gi(v)+gj(v); if(k>bk){bk=k;bi=e;bt=v;}}}
            if(i-1>=0){int e=ED[(size_t)(u-(int)m)]; if(e>=0&&!qd[(size_t)e]){int v=u-(int)m,k=gi(v)+gj(v); if(k>bk){bk=k;bi=e;bt=v;}}}
            if(bi<0)return false; eidx=bi; to=bt; return true; };
        auto adaptivePick=[&](int&eidx,int&frm,int&to)->bool{
            while(!pq.empty()){ int u=pq.top().second; int e,t; if(incidentBest(u,e,t)){eidx=e;frm=u;to=t;return true;} pq.pop(); } return false; };
        auto fallbackPick=[&](int&eidx,int&frm,int&to)->bool{
            while(fptr<E){ int e=order[(size_t)fptr]; fptr+=NUM_AGENTS; if(!qd[(size_t)e]){eidx=e;frm=edges[(size_t)e].a;to=edges[(size_t)e].b;return true;} } return false; };
        auto queryCell=[&](int r,int c)->int{ sendLine("? "+to_string(r)+" "+to_string(c)); string rep=readLine(); return (!rep.empty()&&rep[0]=='1')?1:0; };
        auto pushRoom=[&](int u){ if(!visited[(size_t)u]){visited[(size_t)u]=1;pq.push({gi(u)+gj(u),u});} };

        long long g = envll("GCHUNK", 64); if(g<1)g=1;
        long long SENDCAP = min<long long>(80, max<long long>(1,MAX_MSG_LEN/3));
        long long A0EXP = envll("A0EXP",1); // 1: agent0 also explores; 0: pure coordinator

        if(AGENT_ID!=0){
            vector<int> buf; long long since=0;
            auto flush=[&](){ if(buf.empty())return; string pk; pk.reserve(buf.size()*3);
                for(int e:buf){ pk.push_back((char)(32+(e&63))); pk.push_back((char)(32+((e>>6)&63))); pk.push_back((char)(32+((e>>12)&63))); }
                sendLine("> 0 "+pk); readLine(); buf.clear(); since=0; };
            while(true){ int eidx,frm,to; bool got=adaptivePick(eidx,frm,to); if(!got) got=fallbackPick(eidx,frm,to);
                if(!got){ flush(); sendLine("halt"); return 0; }
                qd[(size_t)eidx]=1; const Edge&ed=edges[(size_t)eidx]; int op=queryCell(ed.r,ed.c); ++since;
                if(op){ buf.push_back(eidx); pushRoom(frm); pushRoom(to); }
                if((long long)buf.size()>=SENDCAP || since>=g) flush(); }
        }
        // AGENT 0: coordinator + (optional) explorer from START
        vector<int> uf((size_t)total); for(long long i=0;i<total;++i)uf[(size_t)i]=(int)i;
        function<int(int)> find=[&](int x){ while(uf[(size_t)x]!=x){uf[(size_t)x]=uf[(size_t)uf[(size_t)x]];x=uf[(size_t)x];} return x; };
        vector<vector<int>> adj((size_t)total); bool connected=false;
        auto addEdge=[&](int eidx){ const Edge&ed=edges[(size_t)eidx]; adj[(size_t)ed.a].push_back(ed.b); adj[(size_t)ed.b].push_back(ed.a); int ra=find(ed.a),rb=find(ed.b); if(ra!=rb)uf[(size_t)ra]=rb; };
        auto processMsg=[&](const string&rep){ size_t p1=rep.find(' '); if(p1==string::npos)return; string body=rep.substr(p1+1);
            for(size_t t=0;t+3<=body.size();t+=3){ int e=((int)(unsigned char)body[t]-32)|(((int)(unsigned char)body[t+1]-32)<<6)|(((int)(unsigned char)body[t+2]-32)<<12); if(e>=0&&e<E) addEdge(e); } };
        long long readEvery = max<long long>(1, g/max<long long>(1,(NUM_AGENTS-1)));
        { const char* re=getenv("READEVERY"); if(re) readEvery=max<long long>(1,atoll(re)); }
        long long sinceRead=0; long long maxAttempts=8*E+400000, attempts=0;
        while(!connected){ if(++attempts>maxAttempts)break;
            int eidx,frm,to; bool own=false;
            if(A0EXP && sinceRead<readEvery){ own=adaptivePick(eidx,frm,to); if(!own) own=fallbackPick(eidx,frm,to); }
            if(own){ qd[(size_t)eidx]=1; const Edge&ed=edges[(size_t)eidx]; int op=queryCell(ed.r,ed.c); ++sinceRead;
                if(op){ addEdge(eidx); pushRoom(frm); pushRoom(to); if(find(START)==find(GOAL))connected=true; } continue; }
            sendLine("< ?"); string rep=readLine(); sinceRead=0; if(rep.empty()||rep[0]=='-')continue; processMsg(rep); if(find(START)==find(GOAL))connected=true; }
        vector<int> par((size_t)total,-2); par[(size_t)START]=-1; { vector<int> q; q.push_back(START); size_t h=0; while(h<q.size()){int u=q[h++]; if(u==GOAL)break; for(int v:adj[(size_t)u])if(par[(size_t)v]==-2){par[(size_t)v]=u;q.push_back(v);} } }
        vector<int> pr; for(int c=GOAL;c!=-1;c=par[(size_t)c]){pr.push_back(c); if(c==START)break;} reverse(pr.begin(),pr.end());
        string mv; for(size_t i=1;i<pr.size();++i){int d=pr[i]-pr[i-1]; if(d==1)mv+="RR";else if(d==-1)mv+="LL";else if(d==(int)m)mv+="DD";else if(d==-(int)m)mv+="UU";}
        sendLine("! "+mv); return 0;
    }

    // ---------- MODE 3: plain full-map (baseline) ----------
    if(MODE==3){
        long long B=(E+NUM_AGENTS-1)/NUM_AGENTS; long long lo=min(E,AGENT_ID*B),hi=min(E,lo+B);
        if(AGENT_ID!=0){
            vector<char> bits((size_t)max<long long>(0,hi-lo),0);
            for(long long e=lo;e<hi;++e){const Edge&ed=edges[(size_t)e]; sendLine("? "+to_string(ed.r)+" "+to_string(ed.c)); string rep=readLine(); bits[(size_t)(e-lo)]=(!rep.empty()&&rep[0]=='1')?1:0;}
            for(long long start=lo;start<hi;start+=chunkBitsCap){ long long cnt=min(chunkBitsCap,hi-start); long long nch=(cnt+5)/6; string pk; pk.reserve((size_t)nch);
                for(long long ci=0;ci<nch;++ci){int val=0;for(int k=0;k<6;++k){long long bi=ci*6+k; if(bi<cnt&&bits[(size_t)((start-lo)+bi)])val|=(1<<k);}pk.push_back((char)(32+val));}
                sendLine("> 0 "+to_string(start)+" "+to_string(cnt)+" "+pk); readLine(); }
            sendLine("halt"); return 0;
        }
        vector<char> ee((size_t)E,0); long long filled=0;
        for(long long e=lo;e<hi;++e){const Edge&ed=edges[(size_t)e]; sendLine("? "+to_string(ed.r)+" "+to_string(ed.c)); string rep=readLine(); ee[(size_t)e]=(!rep.empty()&&rep[0]=='1')?1:0; ++filled;}
        while(filled<E){ sendLine("< ?"); string rep=readLine(); if(rep.empty()||rep[0]=='-')continue;
            size_t p1=rep.find(' '); if(p1==string::npos)continue; string body=rep.substr(p1+1);
            size_t q1=body.find(' '); if(q1==string::npos)continue; long long S=strtoll(body.substr(0,q1).c_str(),0,10);
            size_t q2=body.find(' ',q1+1); if(q2==string::npos)continue; long long cnt=strtoll(body.substr(q1+1,q2-(q1+1)).c_str(),0,10); string pk=body.substr(q2+1);
            for(long long k=0;k<cnt;++k){long long ci=k/6,kk=k%6; if((size_t)ci>=pk.size())break; int val=(int)(unsigned char)pk[(size_t)ci]-32; long long g=S+k; if(g>=0&&g<E)ee[(size_t)g]=(char)((val>>kk)&1);} filled+=cnt; }
        long long total=m*m; vector<vector<int>> adj((size_t)total);
        for(long long e=0;e<E;++e) if(ee[(size_t)e]){adj[(size_t)edges[(size_t)e].a].push_back(edges[(size_t)e].b);adj[(size_t)edges[(size_t)e].b].push_back(edges[(size_t)e].a);}
        vector<int> par((size_t)total,-2); int st=0,gl=(int)(total-1); par[(size_t)st]=-1; vector<int> q; q.push_back(st); size_t h=0;
        while(h<q.size()){int u=q[h++]; if(u==gl)break; for(int v:adj[(size_t)u])if(par[(size_t)v]==-2){par[(size_t)v]=u;q.push_back(v);}}
        vector<int> pr; for(int c=gl;c!=-1;c=par[(size_t)c]){pr.push_back(c); if(c==st)break;} reverse(pr.begin(),pr.end());
        string mv; for(size_t i=1;i<pr.size();++i){int d=pr[i]-pr[i-1]; if(d==1)mv+="RR";else if(d==-1)mv+="LL";else if(d==(int)m)mv+="DD";else if(d==-(int)m)mv+="UU";}
        sendLine("! "+mv); return 0;
    }

    // Common: stride/offset. MODE1 unified: stride=na, offset=AGENT_ID, coordinator=agent0 also queries.
    // MODE2 coordinator: workers only, stride=W=na-1, offset=AGENT_ID-1; agent0 pure reader.
    long long stride = (MODE==1)? NUM_AGENTS : (NUM_AGENTS-1);
    // chunk size in bits: default sqrt-ish but >= producers to keep coordinator synced
    long long producers = (NUM_AGENTS-1);
    long long gdef = (MODE==2) ? producers : max<long long>(producers, (long long)llround(sqrt((double)E)));
    long long g = envll("GCHUNK", gdef);
    if(g<1)g=1; if(g>chunkBitsCap)g=chunkBitsCap;

    // ---------------- WORKER ----------------
    if(!(MODE==2 && AGENT_ID==0) && !(MODE==1 && AGENT_ID==0)){
        long long offset = (MODE==1)? AGENT_ID : (AGENT_ID-1);
        vector<char> mybits; long long k=0,sentK=0;
        for(long long pos=offset;pos<E;pos+=stride){ const Edge&ed=edges[(size_t)order[(size_t)pos]];
            sendLine("? "+to_string(ed.r)+" "+to_string(ed.c)); string rep=readLine();
            mybits.push_back((!rep.empty()&&rep[0]=='1')?1:0); ++k;
            if(k-sentK>=g){ long long cnt=k-sentK; long long nch=(cnt+5)/6; string pk; pk.reserve((size_t)nch);
                for(long long ci=0;ci<nch;++ci){int val=0;for(int b=0;b<6;++b){long long bi=ci*6+b; if(bi<cnt&&mybits[(size_t)(sentK+bi)])val|=(1<<b);}pk.push_back((char)(32+val));}
                sendLine("> 0 "+to_string(sentK)+" "+to_string(cnt)+" "+pk); readLine(); sentK=k; } }
        if(k-sentK>0){ long long cnt=k-sentK; long long nch=(cnt+5)/6; string pk; pk.reserve((size_t)nch);
            for(long long ci=0;ci<nch;++ci){int val=0;for(int b=0;b<6;++b){long long bi=ci*6+b; if(bi<cnt&&mybits[(size_t)(sentK+bi)])val|=(1<<b);}pk.push_back((char)(32+val));}
            sendLine("> 0 "+to_string(sentK)+" "+to_string(cnt)+" "+pk); readLine(); }
        sendLine("halt"); return 0;
    }

    // ---------------- AGENT 0 (coordinator, possibly also querier) ----------------
    long long total=m*m;
    vector<int> uf((size_t)total); for(long long i=0;i<total;++i)uf[(size_t)i]=(int)i;
    function<int(int)> find=[&](int x){ while(uf[(size_t)x]!=x){uf[(size_t)x]=uf[(size_t)uf[(size_t)x]];x=uf[(size_t)x];} return x; };
    vector<vector<int>> adj((size_t)total);
    int START=0,GOAL=(int)(total-1); bool connected=false;
    auto addEdgePos=[&](long long pos){ const Edge&ed=edges[(size_t)order[(size_t)pos]];
        adj[(size_t)ed.a].push_back(ed.b); adj[(size_t)ed.b].push_back(ed.a);
        int ra=find(ed.a),rb=find(ed.b); if(ra!=rb)uf[(size_t)ra]=rb; };
    auto processMsg=[&](const string& rep){ size_t p1=rep.find(' '); if(p1==string::npos)return; long long sender=strtoll(rep.substr(0,p1).c_str(),0,10); long long off=(MODE==1)?sender:(sender-1); string body=rep.substr(p1+1);
        size_t q1=body.find(' '); if(q1==string::npos)return; long long k0=strtoll(body.substr(0,q1).c_str(),0,10);
        size_t q2=body.find(' ',q1+1); if(q2==string::npos)return; long long cnt=strtoll(body.substr(q1+1,q2-(q1+1)).c_str(),0,10); string pk=body.substr(q2+1);
        for(long long t=0;t<cnt;++t){ long long ci=t/6,kk=t%6; if((size_t)ci>=pk.size())break; int val=(int)(unsigned char)pk[(size_t)ci]-32; int bit=(val>>kk)&1; long long pos=off+(k0+t)*stride; if(pos<0||pos>=E)continue; if(bit) addEdgePos(pos); } };

    // agent0 own querying (MODE 1 only)
    bool agent0Queries = (MODE==1);
    long long myoff = 0; long long mypos = agent0Queries? 0 : E; // next own position (stride na)
    // read cadence: reads must keep up with producers => read once per readEvery query-turns
    long long readEvery = agent0Queries? max<long long>(1, g/ max<long long>(1,(NUM_AGENTS-1)) ) : 1;
    long long sinceRead=0;
    long long maxAttempts = 4*E + 200000; long long attempts=0;
    while(!connected){ if(++attempts>maxAttempts)break;
        bool doQuery = agent0Queries && mypos<E && (sinceRead < readEvery);
        if(doQuery){ const Edge&ed=edges[(size_t)order[(size_t)mypos]]; sendLine("? "+to_string(ed.r)+" "+to_string(ed.c)); string rep=readLine();
            if(!rep.empty()&&rep[0]=='1') addEdgePos(mypos); mypos+=NUM_AGENTS; ++sinceRead; if(find(START)==find(GOAL))connected=true; continue; }
        // read
        sendLine("< ?"); string rep=readLine(); sinceRead=0; if(rep.empty()||rep[0]=='-'){ if(!agent0Queries||mypos>=E){ /*nothing to do but wait*/ } continue; }
        processMsg(rep); if(find(START)==find(GOAL))connected=true; }

    vector<int> par((size_t)total,-2); par[(size_t)START]=-1; { vector<int> q; q.push_back(START); size_t h=0; while(h<q.size()){int u=q[h++]; if(u==GOAL)break; for(int v:adj[(size_t)u])if(par[(size_t)v]==-2){par[(size_t)v]=u;q.push_back(v);} } }
    vector<int> pr; for(int c=GOAL;c!=-1;c=par[(size_t)c]){pr.push_back(c); if(c==START)break;} reverse(pr.begin(),pr.end());
    string mv; for(size_t i=1;i<pr.size();++i){int d=pr[i]-pr[i-1]; if(d==1)mv+="RR";else if(d==-1)mv+="LL";else if(d==(int)m)mv+="DD";else if(d==-(int)m)mv+="UU";}
    sendLine("! "+mv); return 0;
}
