#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 2;
vector<int> depth[N];
vector<pair<pair<int, int>, vector<int> > > temp;
vector<pair<int, int> > edge;
vector<pair<vector<int>, vector<int> > > lis;
int ask[N], ans[N], ans1[N];
string s;
void reset(int n) {
  for (int i = 1; i <= n; i++) {
    ask[i] = 0;
  }
}
bool check(int n) {
  for (int i = 1; i <= n; i++) {
    if (ask[i] != 0) {
      return true;
    }
  }
  return false;
}
void query(int n) {
  if (!check(n)) {
    for (int i = 1; i <= n; i++) {
      ans[i] = 0;
    }
    return;
  }
  cout << "? ";
  for (int i = 1; i <= n; i++) {
    cout << ask[i] << ' ';
  }
  cout << endl;
  cin >> s;
  for (int i = 1; i <= n; i++) {
    ans[i] = (s[i - 1] - '0');
  }
}
void query1(int n) {
  if (!check(n)) {
    for (int i = 1; i <= n; i++) {
      ans1[i] = 0;
    }
    return;
  }
  cout << "? ";
  for (int i = 1; i <= n; i++) {
    cout << ask[i] << ' ';
  }
  cout << endl;
  cin >> s;
  for (int i = 1; i <= n; i++) {
    ans1[i] = (s[i - 1] - '0');
  }
}
signed main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  int n, i, j, k, l, z;
  cin >> n;
  depth[0].push_back(1);
  vector<int> haha;
  for (i = 2; i <= n; i++) {
    haha.push_back(i);
  }
  temp.push_back({{1, n - 1}, haha});
  while (temp.size()) {
    vector<pair<pair<int, int>, vector<int> > > oh[2];
    for (z = 0; z < 2; z++) {
      if (temp.size() <= z) {
        continue;
      }
      reset(n);
      for (i = z; i < temp.size(); i += 2) {
        j = temp[i].first.first;
        k = temp[i].first.second;
        if (j == k) {
          for (auto x : temp[i].second) {
            depth[j].push_back(x);
          }
          continue;
        }
        for (l = 0; l < depth[j - 1].size(); l++) {
          ask[depth[j - 1][l]] = (j + k) / 2 - (j - 1) - 1;
        }
      }
      query(n);
      reset(n);
      for (i = z; i < temp.size(); i += 2) {
        j = temp[i].first.first;
        k = temp[i].first.second;
        if (j == k) {
          continue;
        }
        for (l = 0; l < depth[j - 1].size(); l++) {
          ask[depth[j - 1][l]] = (j + k) / 2 - (j - 1);
        }
      }
      query1(n);
      for (i = z; i < temp.size(); i += 2) {
        j = temp[i].first.first;
        k = temp[i].first.second;
        if (j == k) {
          continue;
        }
        vector<int> hix, hix1;
        for (auto x : temp[i].second) {
          if (ans[x]) {
            hix.push_back(x);
          }
          if (ans1[x] && !ans[x]) {
            depth[(j + k) / 2].push_back(x);
          }
          if (!ans1[x]) {
            hix1.push_back(x);
          }
        }
        if (hix.size()) {
          oh[z].push_back({{j, (j + k) / 2 - 1}, hix});
        }
        if (hix1.size()) {
          oh[z].push_back({{(j + k) / 2 + 1, k}, hix1});
        }
      }
    }
    temp.clear();
    j = k = 0;
    while (j < oh[0].size() && k < oh[1].size()) {
      if (oh[0][j].first.first < oh[1][k].first.first) {
        temp.push_back(oh[0][j]);
        j++;
      } else {
        temp.push_back(oh[1][k]);
        k++;
      }
    }
    while (j < oh[0].size()) {
      temp.push_back(oh[0][j]);
      j++;
    }
    while (k < oh[1].size()) {
      temp.push_back(oh[1][k]);
      k++;
    }
  }
  temp.clear();
  for (z = 0; z < 3; z++) {
    for (i = z; i < n - 1; i += 3) {
      if (!depth[i + 1].size()) {
        break;
      }
      lis.push_back({depth[i], depth[i + 1]});
    }
    while (lis.size()) {
      vector<pair<vector<int>, vector<int> > > temp;
      reset(n);
      for (i = 0; i < lis.size(); i++) {
        if (lis[i].first.size() == 1) {
          for (auto x : lis[i].second) {
            edge.push_back({x, lis[i].first.front()});
          }
          continue;
        }
        for (j = 0; j < lis[i].first.size() / 2; j++) {
          ask[lis[i].first[j]] = 1;
        }
      }
      query(n);
      for (i = 0; i < lis.size(); i++) {
        if (lis[i].first.size() == 1) {
          continue;
        }
        vector<int> hix, hix1, huhu, huhu1;
        for (j = 0; j < lis[i].first.size(); j++) {
          if (j < lis[i].first.size() / 2) {
            hix.push_back(lis[i].first[j]);
          } else {
            hix1.push_back(lis[i].first[j]);
          }
        }
        for (j = 0; j < lis[i].second.size(); j++) {
          if (ans[lis[i].second[j]]) {
            huhu.push_back(lis[i].second[j]);
          } else {
            huhu1.push_back(lis[i].second[j]);
          }
        }
        if (huhu.size()) {
          temp.push_back({hix, huhu});
        }
        if (huhu1.size()) {
          temp.push_back({hix1, huhu1});
        }
      }
      swap(temp, lis);
    }
  }
  cout << "!\n";
  for (i = 0; i < edge.size(); i++) {
    cout << edge[i].first << ' ' << edge[i].second << '\n';
  }
  return 0;
}
