#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-9;
const int MAXB = 10;
const int MAXN = 1025;
vector<int> distGroup[MAXN];
int hasDist[MAXN];
int predecessor[MAXN];
vector<int> output;
set<int> centers;
string result, resultm;
int maxDist[MAXN];
int minDist[MAXN];
vector<string> strangeresults;
int main() {
  int N;
  cin >> N;
  for (int i = (0); i < (N); i++) minDist[i] = 1;
  for (int i = (0); i < (N); i++) maxDist[i] = (1 << MAXB) - 1;
  for (int i = (0); i < (N); i++) hasDist[i] = -1;
  for (int i = (0); i < (N); i++) distGroup[i].clear();
  distGroup[0].push_back(0);
  maxDist[0] = minDist[0] = hasDist[0] = 0;
  int largest = 0;
  for (int p = int(MAXB) - 1; p >= (0); p--) {
    for (int s = (0); s < (2); s++) {
      output = vector<int>(N, 0);
      centers.clear();
      for (int i = (s << (p + 1)); true; i += (4 << p)) {
        if (i > N || int((distGroup[i]).size()) == 0) break;
        for (auto n : distGroup[i]) {
          assert(output[n] == 0);
          output[n] = (1 << p);
        }
        centers.insert(i);
      }
      if (int((centers).size()) > 0) {
        cout << "?";
        for (auto v : output) cout << " " << min(N - 1, v);
        cout << endl << flush;
        cin >> result;
        cout << "?";
        for (auto v : output) cout << " " << max(0, min(N - 1, v - 1));
        cout << endl << flush;
        cin >> resultm;
        while (int((result).size()) != N || int((resultm).size()) != N) {
          cerr << "VERY STRANGE!! got \"" << result << "\" and \"" << resultm
               << "\" as results" << endl
               << flush;
          strangeresults.push_back(result);
          strangeresults.push_back(resultm);
          if (int((strangeresults).size()) == (N - 1) * 2) {
            cout << "!" << endl;
            for (int i = (0); i < (N - 1); i++)
              cout << strangeresults[i * 2] << " " << strangeresults[i * 2 + 1]
                   << endl;
            return 0;
          }
          cout << "?";
          for (auto v : output) cout << " " << min(N - 1, v);
          cout << endl << flush;
          cin >> result;
          cout << "?";
          for (auto v : output) cout << " " << max(0, min(N - 1, v - 1));
          cout << endl << flush;
          cin >> resultm;
        }
        for (int i = (0); i < (N); i++) {
          if (minDist[i] == maxDist[i]) continue;
          if (centers.find(minDist[i] - 1) != centers.end()) {
            if (result[i] == '1') {
              if (resultm[i] == '1') {
                maxDist[i] -= (1 << p);
              } else {
                minDist[i] = maxDist[i] = minDist[i] - 1 + (1 << p);
              }
            } else
              minDist[i] += (1 << p);
          }
          if (minDist[i] == maxDist[i]) {
            hasDist[i] = minDist[i];
            largest = max(largest, minDist[i]);
            distGroup[minDist[i]].push_back(i);
          }
        }
      }
    }
  }
  for (int i = (0); i < (N); i++) predecessor[i] = -1;
  for (int i = (0); i < (N); i++)
    assert(minDist[i] == maxDist[i] && maxDist[i] == hasDist[i]);
  for (int a = (0); a < (2); a++) {
    vector<string> results;
    for (int b = (0); b < (MAXB); b++) {
      for (int xo = (0); xo < (2); xo++) {
        cout << "?";
        for (int n = (0); n < (N); n++) {
          if (((hasDist[n] >> 1) ^ a) & 1)
            cout << " " << (((n >> b) ^ xo) & 1);
          else
            cout << " 0";
        }
        cout << endl << flush;
        string tmp;
        cin >> tmp;
        results.push_back(tmp);
      }
    }
    for (int d = (0); d < (largest); d++) {
      if (((d >> 1) ^ a ^ 1) & 1) continue;
      for (auto n1 : distGroup[d])
        for (auto n2 : distGroup[d + 1]) {
          bool ok = true;
          for (int b = (0); b < (MAXB); b++) {
            if (results[b * 2 + (1 ^ ((n1 >> b) & 1))][n2] == '0') ok = false;
          }
          if (ok) {
            if (predecessor[n2] != -1) {
              cerr << "prev predecessor[" << n2 << "]=" << predecessor[n2]
                   << endl;
              cerr << predecessor[n2] << endl;
            }
            assert(predecessor[n2] == -1);
            predecessor[n2] = n1;
          }
        }
    }
  }
  assert(predecessor[0] == -1);
  for (int i = (1); i < (N); i++) assert(predecessor[i] != -1);
  cout << "!" << endl << flush;
  for (int i = (1); i < (N); i++)
    cout << predecessor[i] + 1 << " " << i + 1 << endl;
  return 0;
}
