Problem: cf1023_e
Difficulty: easy
Categories: greedy
Time limit: 1000 ms, memory limit: 256 MB

This is an interactive problem.

Bob lives in a square grid of size $n \times n$, with rows numbered $1$ through $n$ from top to bottom, and columns numbered $1$ through $n$ from left to right. Every cell is either allowed or blocked, but you don't know the exact description of the grid. You are given only an integer $n$.

Bob can move through allowed cells but only in some limited directions. When Bob is in an allowed cell in the grid, he can move down or right to an adjacent cell, if it is allowed.

You can ask at most $4 \cdot n$ queries of form "? $r_1$ $c_1$ $r_2$ $c_2$" ($1 \le r_1 \le r_2 \le n$, $1 \le c_1 \le c_2 \le n$). The answer will be "YES" if Bob can get from a cell $(r_1, c_1)$ to a cell $(r_2, c_2)$, and "NO" otherwise. In particular, if one of the two cells (or both) is a blocked cell then the answer is "NO" for sure. Since Bob doesn't like short trips, you can only ask queries with the manhattan distance between the two cells at least $n - 1$, i.e. the following condition must be satisfied: $(r_2 - r_1) + (c_2 - c_1) \ge n - 1$.

It's guaranteed that Bob can get from the top-left corner $(1, 1)$ to the bottom-right corner $(n, n)$ and your task is to find a way to do it. You should print the answer in form "! S" where $S$ is a string of length $2 \cdot n - 2$ consisting of characters 'D' and 'R', denoting moves down and right respectively. The down move increases the first coordinate by $1$, the right move increases the second coordinate by $1$. If there are multiple solutions, any of them will be accepted. You should terminate immediately after printing the solution.

Input

The only line of the input contains an integer $n$ ($2 \le n \le 500$) — the size of the grid.

Output

When you are ready to print the answer, print a single line containing "! S" where where $S$ is a string of length $2 \cdot n - 2$ consisting of characters 'D' and 'R', denoting moves down and right respectively. The path should be a valid path going from the cell $(1, 1)$ to the cell $(n, n)$ passing only through allowed cells.

Interaction

You can ask at most $4 \cdot n$ queries. To ask a query, print a line containing "? $r_1$ $c_1$ $r_2$ $c_2$" ($1 \le r_1 \le r_2 \le n$, $1 \le c_1 \le c_2 \le n$). After that you should read a single line containing "YES" or "NO" depending on the answer of the query. "YES" means Bob can go from the cell $(r_1, c_1)$ to the cell $(r_2, c_2)$, "NO" means the opposite.

Note that the grid is fixed before the start of your solution and does not depend on your queries.

After printing a query do not forget to output end of line and flush the output. Otherwise you will get Idleness limit exceeded or other negative verdict. To do this, use:

* fflush(stdout) or cout.flush() in C++;
* System.out.flush() in Java;
* flush(output) in Pascal;
* stdout.flush() in Python;
* see documentation for other languages.

Answer "BAD" instead of "YES" or "NO" means that you made an invalid query. Exit immediately after receiving "BAD" and you will see Wrong answer verdict. Otherwise you can get an arbitrary verdict because your solution will continue to read from a closed stream.

Example

Input

```
4  
   
YES  
   
NO  
   
YES  
   
YES  
 
```

Output

```
   
? 1 1 4 4  
   
? 1 2 4 3  
   
? 4 1 4 4  
   
? 1 4 4 4  
   
! RDRRDD
```

Note

The first example is shown on the picture below.

 ![](https://espresso.codeforces.com/4bcdeab2ec8d0a3c5e6d71bf5a192d3236646d15.png) 

Non-adaptive interactor (C++):
#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;

static long long queries = 0;
static long long query_limit = 0;

static void log_metrics() {
    try {
        tout << "queries=" << queries << '\n';
        tout << "query_limit=" << query_limit << '\n';
        tout.flush();
    } catch (...) {
        
    }
}

static void finish(TResult verdict, const string& msg) {
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}

static inline uint64_t maskRangeBits(int l, int r) { 
    if (l > r) return 0;
    uint64_t left = (l == 0) ? ~0ull : (~0ull << l);
    uint64_t right = (r == 63) ? ~0ull : ((1ull << (r + 1)) - 1ull);
    return left & right;
}

static void propagateRightWords(const uint64_t* A, const uint64_t* M, uint64_t* B, int W) {
    bool carry = false;
    for (int w = 0; w < W; w++) {
        uint64_t mw = M[w];
        uint64_t aw = A[w] & mw;
        uint64_t bw = 0;

        uint64_t x = mw;
        while (x) {
            int start = __builtin_ctzll(x);
            uint64_t y = x >> start;

            int len;
            uint64_t noty = ~y;
            if (noty == 0ull) len = 64 - start;
            else len = __builtin_ctzll(noty);

            uint64_t segMask;
            if (len == 64) segMask = ~0ull;
            else segMask = ((1ull << len) - 1ull) << start;

            uint64_t segA = aw & segMask;
            bool segSeedFromCarry = carry && (start == 0);

            if (segA || segSeedFromCarry) {
                int seedPos = segSeedFromCarry ? 0 : __builtin_ctzll(segA);
                uint64_t fillMask = segMask & (~0ull << seedPos);
                bw |= fillMask;
            }

            x &= ~segMask;
        }

        B[w] = bw;
        carry = ((bw >> 63) & 1ull) != 0;
    }
}

struct GridJudge {
    int n = 0;
    int W = 0; 
    vector<array<uint64_t, 8>> rowAllowed; 

    bool cellAllowed(int r, int c) const {
        int idx = c - 1;
        int w = idx >> 6;
        int b = idx & 63;
        return (rowAllowed[r][w] >> b) & 1ull;
    }

    bool reachableRect(int r1, int c1, int r2, int c2) const {
        if (r1 > r2 || c1 > c2) return false;
        if (!cellAllowed(r1, c1) || !cellAllowed(r2, c2)) return false;

        uint64_t interval[8] = {0, 0, 0, 0, 0, 0, 0, 0};
        int lIdx = c1 - 1;
        int rIdx = c2 - 1;
        int sw = lIdx >> 6, sb = lIdx & 63;
        int ew = rIdx >> 6, eb = rIdx & 63;

        if (sw == ew) {
            interval[sw] = maskRangeBits(sb, eb);
        } else {
            interval[sw] = maskRangeBits(sb, 63);
            for (int w = sw + 1; w <= ew - 1; w++) interval[w] = ~0ull;
            interval[ew] = maskRangeBits(0, eb);
        }
        for (int w = W; w < 8; w++) interval[w] = 0;

        uint64_t prev[8] = {0, 0, 0, 0, 0, 0, 0, 0};
        uint64_t cur[8] = {0, 0, 0, 0, 0, 0, 0, 0};
        uint64_t A[8] = {0, 0, 0, 0, 0, 0, 0, 0};
        uint64_t M[8] = {0, 0, 0, 0, 0, 0, 0, 0};

        for (int r = r1; r <= r2; r++) {
            for (int w = 0; w < W; w++) M[w] = rowAllowed[r][w] & interval[w];
            for (int w = W; w < 8; w++) M[w] = 0;

            if (r == r1) {
                for (int w = 0; w < 8; w++) A[w] = 0;
                int idx = c1 - 1;
                int ww = idx >> 6;
                int bb = idx & 63;
                A[ww] |= (1ull << bb);
                for (int w = 0; w < W; w++) A[w] &= M[w];
            } else {
                for (int w = 0; w < W; w++) A[w] = prev[w] & M[w];
                for (int w = W; w < 8; w++) A[w] = 0;
            }

            propagateRightWords(A, M, cur, W);

            for (int w = 0; w < 8; w++) prev[w] = cur[w];
        }

        int idx = c2 - 1;
        int ww = idx >> 6;
        int bb = idx & 63;
        return ((prev[ww] >> bb) & 1ull) != 0;
    }
};

int main(int argc, char** argv) {
    registerInteraction(argc, argv);
    atexit(log_metrics);

    GridJudge J;
    J.n = inf.readInt(2, 500, "n");
    J.W = (J.n + 63) / 64;
    J.rowAllowed.assign(J.n + 1, array<uint64_t, 8>{0, 0, 0, 0, 0, 0, 0, 0});

    for (int r = 1; r <= J.n; r++) {
        string s = inf.readToken();
        if ((int)s.size() != J.n) finish(_pe, "invalid hidden grid row length");
        for (int c = 1; c <= J.n; c++) {
            char ch = s[c - 1];
            if (ch != '.' && ch != '#') finish(_pe, "invalid hidden grid char");
            if (ch == '.') {
                int idx = c - 1;
                int w = idx >> 6;
                int b = idx & 63;
                J.rowAllowed[r][w] |= (1ull << b);
            }
        }
    }

    query_limit = 4LL * J.n;
    long long hard_cap = max(200000LL, 10LL * query_limit);

    log_metrics(); 

    cout << J.n << endl; 
    cout.flush();

    while (true) {
        string t;
        if (!(cin >> t)) finish(_pe, "unexpected EOF from contestant");

        if (t == "?") {
            long long r1, c1, r2, c2;
            if (!(cin >> r1 >> c1 >> r2 >> c2)) finish(_pe, "malformed query");
            queries++;
            if (queries > hard_cap) finish(_pe, "hard cap exceeded");

            bool ok = true;
            ok = ok && (1 <= r1 && r1 <= r2 && r2 <= J.n);
            ok = ok && (1 <= c1 && c1 <= c2 && c2 <= J.n);
            ok = ok && ((r2 - r1) + (c2 - c1) >= (J.n - 1));

            if (!ok) {
                cout << "BAD" << endl;
                cout.flush();
                finish(_pe, "invalid query constraints");
            }

            bool ans = J.reachableRect((int)r1, (int)c1, (int)r2, (int)c2);
            cout << (ans ? "YES" : "NO") << endl;
            cout.flush();
        } else if (t == "!") {
            string s;
            if (!(cin >> s)) finish(_pe, "missing answer string");

            if ((int)s.size() != 2 * J.n - 2) finish(_wa, "wrong answer length");

            int r = 1, c = 1;
            if (!J.cellAllowed(r, c)) finish(_wa, "start cell blocked");
            for (char ch : s) {
                if (ch == 'D') r++;
                else if (ch == 'R') c++;
                else finish(_wa, "invalid move character");
                if (r < 1 || r > J.n || c < 1 || c > J.n) finish(_wa, "moved out of grid");
                if (!J.cellAllowed(r, c)) finish(_wa, "stepped on blocked cell");
            }
            if (r != J.n || c != J.n) finish(_wa, "did not reach target");

            finish(_ok, "correct");
        } else {
            finish(_pe, "unknown token from contestant");
        }
    }
}


Adaptive interactor (C++):
#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;

static long long queries = 0;
static long long query_limit = 0;

static void log_metrics() {
    try {
        tout << "queries=" << queries << "\n";
        tout << "query_limit=" << query_limit << "\n";
        tout.flush();
    } catch (...) {
        
    }
}

static void finish(TResult verdict, const string& msg) {
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}

struct Corridor {
    
    
    int n = 0;
    int mode = 0;

    bool allowed(int r, int c) const {
        if (mode == 0) return (r == 1) || (c == n);
        return (c == 1) || (r == n);
    }

    int pos(int r, int c) const {
        
        if (!allowed(r, c)) return -1;
        if (mode == 0) {
            
            if (r == 1) return c - 1;
            
            return (n - 1) + (r - 1);
        } else {
            
            if (c == 1) return r - 1;
            
            return (n - 1) + (c - 1);
        }
    }

    string canonicalPathString() const {
        string s;
        s.reserve(2 * n - 2);
        if (mode == 0) {
            s.append(n - 1, 'R');
            s.append(n - 1, 'D');
        } else {
            s.append(n - 1, 'D');
            s.append(n - 1, 'R');
        }
        return s;
    }
};

static bool readToken(string& tok) {
    if (!(cin >> tok)) return false;
    return true;
}

static bool readIntLL(long long& x) {
    if (!(cin >> x)) return false;
    return true;
}

static bool isAllDR(const string& s) {
    for (char ch : s) if (ch != 'D' && ch != 'R') return false;
    return true;
}

int main(int argc, char** argv) {
    registerInteraction(argc, argv);
    atexit(log_metrics);

    int n = inf.readInt();
    if (n < 2 || n > 500) {
        query_limit = 0;
        log_metrics();
        finish(_pe, "invalid n in input");
    }

    query_limit = 4LL * n;

    
    log_metrics();

    cout << n << "\n";
    cout.flush();

    Corridor corr;
    corr.n = n;
    corr.mode = 0; 
    bool modeChosen = false;

    const long long hard_cap = max(200000LL, 10LL * query_limit);

    while (true) {
        string t;
        if (!readToken(t)) {
            finish(_pe, "unexpected EOF from contestant");
        }

        if (t == "?") {
            long long r1, c1, r2, c2;
            if (!readIntLL(r1) || !readIntLL(c1) || !readIntLL(r2) || !readIntLL(c2)) {
                cout << "BAD\n";
                cout.flush();
                finish(_pe, "malformed query: expected 4 integers");
            }

            if (r1 < 1 || r1 > n || r2 < 1 || r2 > n || c1 < 1 || c1 > n || c2 < 1 || c2 > n) {
                cout << "BAD\n";
                cout.flush();
                finish(_pe, "query out of bounds");
            }
            if (r1 > r2 || c1 > c2) {
                cout << "BAD\n";
                cout.flush();
                finish(_pe, "query violates r1<=r2 and c1<=c2");
            }

            long long dist = (r2 - r1) + (c2 - c1);
            if (dist < n - 1) {
                cout << "BAD\n";
                cout.flush();
                finish(_pe, "query violates manhattan distance restriction");
            }

            queries++;
            if (queries > hard_cap) {
                cout << "BAD\n";
                cout.flush();
                finish(_pe, "too many queries (hard cap exceeded)");
            }

            if (!modeChosen) {
                
                unsigned long long h = 1469598103934665603ULL;
                auto mix = [&](unsigned long long v) {
                    h ^= v + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);
                };
                mix((unsigned long long)r1);
                mix((unsigned long long)c1);
                mix((unsigned long long)r2);
                mix((unsigned long long)c2);
                corr.mode = (int)(h & 1ULL); 
                modeChosen = true;
            }

            int p1 = corr.pos((int)r1, (int)c1);
            int p2 = corr.pos((int)r2, (int)c2);

            if (p1 == -1 || p2 == -1 || p1 > p2) {
                cout << "NO\n";
            } else {
                cout << "YES\n";
            }
            cout.flush();
            continue;
        }

        if (t == "!") {
            string s;
            if (!readToken(s)) {
                finish(_pe, "malformed answer: expected a path string");
            }

            if (!modeChosen) {
                
                corr.mode = 0;
                modeChosen = true;
            }

            if ((int)s.size() != 2 * n - 2) finish(_wa, "wrong path length");
            if (!isAllDR(s)) finish(_wa, "path contains invalid characters");

            int cntR = 0, cntD = 0;
            for (char ch : s) (ch == 'R' ? cntR : cntD)++;
            if (cntR != n - 1 || cntD != n - 1) finish(_wa, "wrong number of moves");

            int r = 1, c = 1;
            if (!corr.allowed(r, c)) finish(_wa, "start cell blocked (internal error)");
            for (char ch : s) {
                if (ch == 'D') r++;
                else c++;
                if (r < 1 || r > n || c < 1 || c > n) finish(_wa, "path goes out of bounds");
                if (!corr.allowed(r, c)) finish(_wa, "path steps on a blocked cell");
            }
            if (r != n || c != n) finish(_wa, "path does not end at (n,n)");

            finish(_ok, "OK");
        }

        
        finish(_pe, "unexpected token from contestant");
    }
}


Test generator (C++):
#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;

static bool hasOptName(int argc, char** argv, const string& longName, const string& shortName) {
    string longKey = "--" + longName;
    string shortKey = "-" + shortName;
    for (int i = 2; i < argc; i++) { 
        string s = argv[i];
        if (s == longKey || s == shortKey) return true;
        if (s.rfind(longKey + "=", 0) == 0) return true;
    }
    return false;
}

static string buildAlternatingRunsPath(int n, int maxRun) {
    int remR = n - 1, remD = n - 1;
    string p;
    p.reserve(2 * n - 2);

    char dir = rnd.next(0, 1) ? 'R' : 'D';
    while (remR > 0 || remD > 0) {
        if (dir == 'R' && remR == 0) dir = 'D';
        if (dir == 'D' && remD == 0) dir = 'R';

        int& rem = (dir == 'R' ? remR : remD);
        int runMax = min(maxRun, rem);
        int runLen = rnd.next(1, runMax);
        p.append(runLen, dir);
        rem -= runLen;

        if (remR == 0 && remD == 0) break;

        
        bool canFlip = (dir == 'R' ? (remD > 0) : (remR > 0));
        if (!canFlip) continue;

        bool flip = true;
        if (rnd.next(1, 10) == 1) flip = false; 
        if (flip) dir = (dir == 'R' ? 'D' : 'R');
    }

    if ((int)p.size() != 2 * n - 2) {
        
        p.clear();
        p.append(n - 1, 'R');
        p.append(n - 1, 'D');
    }
    return p;
}

static vector<string> gridFromPath(int n, const string& path) {
    vector<string> g(n, string(n, '#'));
    int r = 0, c = 0;
    g[r][c] = '.';
    for (char ch : path) {
        if (ch == 'D') r++;
        else c++;
        if (r < 0 || r >= n || c < 0 || c >= n) break;
        g[r][c] = '.';
    }
    
    g[0][0] = '.';
    g[n - 1][n - 1] = '.';
    return g;
}

int main(int argc, char** argv) {
    registerGen(argc, argv, 1);

    string mode = opt<string>("mode", "non");
    int nOpt = opt<int>("n", 500);
    int maxRun = opt<int>("maxRun", 7);

    bool nForced = hasOptName(argc, argv, "n", "n");
    int seed = atoi(argv[1]);

    int n = nOpt;
    if (!nForced) {
        if (seed == 1) n = 2;          
        else if (seed == 2) n = 500;   
        else if (seed == 3) n = 7;     
        else n = min(500, max(2, nOpt));
    }
    n = min(500, max(2, n));
    maxRun = min(50, max(1, maxRun));

    if (mode == "adp") {
        
        cout << n << "\n";
        return 0;
    }

    if (mode != "non") {
        
        mode = "non";
    }

    string path;
    if (seed == 1) {
        path = "RD"; 
    } else if (seed == 2) {
        path.assign(n - 1, 'R');
        path.append(n - 1, 'D'); 
    } else if (seed == 3) {
        
        path = "RDRDRD"; 
        int usedR = 3, usedD = 3;
        int remR = (n - 1) - usedR;
        int remD = (n - 1) - usedD;
        
        char dir = 'R';
        while (remR > 0 || remD > 0) {
            if (dir == 'R' && remR == 0) dir = 'D';
            if (dir == 'D' && remD == 0) dir = 'R';
            if (dir == 'R') {
                path.push_back('R');
                remR--;
                dir = 'D';
            } else {
                path.push_back('D');
                remD--;
                dir = 'R';
            }
        }
    } else {
        
        path = buildAlternatingRunsPath(n, maxRun);

        
        
        
        if (n >= 10 && (int)path.size() == 2 * n - 2) {
            int block = min(20, 2 * n - 2);
            int pos = rnd.next(0, (2 * n - 2) - block);
            string sub = path.substr(pos, block);
            stable_sort(sub.begin(), sub.end(), [&](char a, char b) {
                
                bool rFirst = (rnd.next(0, 1) == 1);
                if (a == b) return false;
                if (rFirst) return a == 'R' && b == 'D';
                return a == 'D' && b == 'R';
            });
            for (int i = 0; i < block; i++) path[pos + i] = sub[i];
        }
    }

    
    int cntR = 0, cntD = 0;
    for (char ch : path) (ch == 'R' ? cntR : cntD)++;
    if ((int)path.size() != 2 * n - 2 || cntR != n - 1 || cntD != n - 1) {
        path.assign(n - 1, 'R');
        path.append(n - 1, 'D');
    }

    vector<string> g = gridFromPath(n, path);

    cout << n << "\n";
    for (int i = 0; i < n; i++) cout << g[i] << "\n";
    return 0;
}