#include <bits/stdc++.h>
const int MAXN = 1000 + 5;
char str[MAXN];
int n;
inline std::vector<int> query(std::vector<int> d) {
  std::vector<int> ans;
  printf("? ");
  for (auto x : d) printf("%d ", x);
  puts("");
  std::fflush(stdout);
  scanf("%s", str + 1);
  for (int i = 1; i <= n; ++i) ans.push_back(str[i] - '0');
  return ans;
}
std::vector<int> G[MAXN];
std::vector<int> node[MAXN * 50];
int tot = 1;
struct Node {
  int l, r, id;
  Node(int l = 0, int r = 0, int id = 0) : l(l), r(r), id(id) {}
  inline bool operator<(const Node &t) const { return l < t.l; }
};
int fa[MAXN];
inline void work(std::vector<int> id, int bit) {
  std::vector<int> d;
  d.resize(n);
  for (auto x : id) {
    for (auto y : G[x - 1])
      if ((y >> bit) & 1) d[y - 1] = 1;
  }
  std::vector<int> a;
  a = query(d);
  for (auto x : id) {
    for (auto y : G[x]) fa[y] |= (a[y - 1] << bit);
  }
}
bool tag[MAXN];
int main() {
  scanf("%d", &n);
  std::vector<Node> now;
  G[0].push_back(1);
  now.push_back(Node(0, n, 1));
  for (int i = 2; i <= n; ++i) node[tot].push_back(i);
  while (!now.empty()) {
    std::vector<Node> v1, v2;
    std::sort(now.begin(), now.end());
    for (int i = 0; i < now.size(); i += 2) {
      v1.push_back(now[i]);
      if (i + 1 < now.size()) v2.push_back(now[i + 1]);
    }
    std::vector<int> d, a1, a2;
    d.resize(n);
    now.clear();
    memset(tag, 0, sizeof(tag));
    for (auto x : v1) {
      int mid = (x.l + x.r) >> 1;
      assert(x.l < x.r - 1);
      for (auto y : G[x.l]) d[y - 1] = mid - x.l - 1, tag[y - 1] = 1;
    }
    a1 = query(d);
    for (int i = 0; i <= n - 1; ++i)
      if (tag[i]) d[i]++;
    a2 = query(d);
    for (auto x : v1) {
      int mid = (x.l + x.r) >> 1;
      Node ls = Node(x.l, mid, ++tot), rs = Node(mid, x.r, ++tot);
      for (auto y : node[x.id]) {
        if (!a1[y - 1] && a2[y - 1])
          G[mid].push_back(y);
        else if (a1[y - 1])
          node[ls.id].push_back(y);
        else
          node[rs.id].push_back(y);
      }
      if (ls.l + 1 < ls.r) now.push_back(ls);
      if (rs.l + 1 < rs.r) now.push_back(rs);
    }
    d.clear();
    d.resize(n);
    memset(tag, 0, sizeof(tag));
    for (auto x : v2) {
      int mid = (x.l + x.r) >> 1;
      assert(x.l < x.r - 1);
      for (auto y : G[x.l]) d[y - 1] = mid - x.l - 1, tag[y - 1] = 1;
    }
    a1 = query(d);
    for (int i = 0; i <= n - 1; ++i)
      if (tag[i]) d[i]++;
    a2 = query(d);
    for (auto x : v2) {
      int mid = (x.l + x.r) >> 1;
      Node ls = Node(x.l, mid, ++tot), rs = Node(mid, x.r, ++tot);
      for (auto y : node[x.id]) {
        if (!a1[y - 1] && a2[y - 1])
          G[mid].push_back(y);
        else if (a1[y - 1])
          node[ls.id].push_back(y);
        else
          node[rs.id].push_back(y);
      }
      if (ls.l + 1 < ls.r) now.push_back(ls);
      if (rs.l + 1 < rs.r) now.push_back(rs);
    }
  }
  for (int i = 0; i <= 9; ++i) {
    std::vector<int> v1, v2, v3;
    for (int i = 1; i < n; i += 3) {
      v1.push_back(i);
      if (i + 1 < n) v2.push_back(i + 1);
      if (i + 2 < n) v3.push_back(i + 2);
    }
    work(v1, i);
    work(v2, i);
    work(v3, i);
  }
  puts("!");
  for (int i = 2; i <= n; ++i) printf("%d %d\n", fa[i], i);
  std::fflush(stdout);
  return 0;
}
