#include<stdio.h>
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<string.h>

#ifdef LOCAL
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
#else
#define NDEBUG
#define eprintf(...) do {} while (0)
#endif
#include<cassert>

using namespace std;

typedef long long LL;
typedef vector<int> VI;

#define REP(i,n) for(int i=0, i##_len=(n); i<i##_len; ++i)
#define EACH(i,c) for(__typeof((c).begin()) i=(c).begin(),i##_end=(c).end();i!=i##_end;++i)

template<class T> inline void amin(T &x, const T &y) { if (y<x) x=y; }
template<class T> inline void amax(T &x, const T &y) { if (x<y) x=y; }
template<class Iter> void rprintf(const char *fmt, Iter begin, Iter end) {
    for (bool sp=0; begin!=end; ++begin) { if (sp) putchar(' '); else sp = true; printf(fmt, *begin); }
    putchar('\n');
}

struct UnionFind {
    int n, cc, *u;
    UnionFind() : n(0), cc(0), u(NULL) {}
    UnionFind(int n_) : n(n_), cc(n_) {
	u = new int[n_];
	memset(u, -1, sizeof (int) * n);
    }
    UnionFind(const UnionFind &y) : n(y.n), cc(y.cc) {
	u = new int[y.n];
	memcpy(u, y.u, sizeof (int) * n);
    }
    ~UnionFind() {
	delete[] u; u = NULL;
	n = cc = 0;
    }
    friend void swap(UnionFind &x, UnionFind &y) {
	swap(x.n, y.n); swap(x.cc, y.cc); swap(x.u, y.u);
    }
    UnionFind& operator=(UnionFind y) { 
	swap(*this, y);
	return *this;
    }
    int root(int x) {
	int y = x, t;
	while (u[y] >= 0) y = u[y];
	while (x != y) { t = u[x]; u[x] = y; x = t; }
	return y;
    }
    bool link(int x, int y) {
	x = root(x); y = root(y);
	if (x == y) return false;
	if (u[y] < u[x]) swap(x, y);
	u[x] += u[y]; u[y] = x; cc--;
	return true;
    }
    bool same(int x, int y) { return root(x) == root(y); }
    int size(int x) { return -u[root(x)]; }
    int count() { return cc; }
};

int N;
int A, B;
char ans[4011];
int cnt;

char query(int a, int b) {
    cnt++;
    assert(cnt <= 2*N);
    printf("? %d %d\n", a, b);
    fflush(stdout);
    char buf[11];
    scanf("%s", buf);
    return *buf;
}

void solve() {
    N = A+B;
    UnionFind U(N+2);
    const int T = N, F = N+1;
    VI cur;
    cur.reserve(N);
    REP (i, N) cur.push_back(i);

    while (cur.size() > 2u) {
	VI nxt;
	for (int i=0; i+1<(int)cur.size(); i+=2) {
	    char c = query(cur[i], cur[i+1]);
	    if (c == 'Y') {
		c = query(cur[i+1], cur[i]);
		if (c == 'Y') {
		    U.link(cur[i], cur[i+1]);
		    nxt.push_back(cur[i]);
		} else {
		    U.link(F, cur[i]);
		}
	    }
	}

	if (cur.size() % 2 == 1 && nxt.size() % 2 == 0) nxt.push_back(cur.back());
	swap(cur, nxt);
    }

    int root = cur[0];
    U.link(T, cur[0]);
    if (cur.size() == 2u) {
	U.link(cur[0], cur[1]);
    }

    VI z;
    REP (i, N) if (U.root(i) == i && !U.same(i, F) && !U.same(i, T)) {
	z.push_back(i);
    }
    REP (j, (int)z.size()-1) {
	int v = z[j];
	char c = query(root, v);
	if (c == 'Y') {
	    U.link(v, T);
	} else {
	    U.link(v, F);
	}
    }

    int a_cnt = 0;
    REP (i, N) {
	if (U.same(i, T)) { ans[i] = '1'; a_cnt++; }
	else if (U.same(i, F)) { ans[i] = '0'; }
    }

    REP (i, N) if (!U.same(i, F) && !U.same(i, T)) {
	if (a_cnt < A) {
	    ans[i] = '1';
	} else {
	    ans[i] = '0';
	}
    }

    ans[N] = 0;
    printf("! %s\n", ans);
}

void MAIN() {
    scanf("%d%d", &A, &B);
    if (A > B) {
	solve();
    } else {
	puts("Impossible");
    }
}

int main() {
    int TC = 1;
//    scanf("%d", &TC);
    REP (tc, TC) MAIN();
    return 0;
}



Measured memory_bytes: 848