#include <bits/stdc++.h>
const int maxn = 1e2 + 10, mod = 1e9 + 7;
using namespace std;
int n, m, k, t;
int cnt[maxn][26];
vector<string> ret[3];
char ans[maxn];
void ask(int id, int l, int r) {
  if (l > r) return;
  printf("? %d %d\n", l, r);
  fflush(stdout);
  for (int i = 1; i <= (r - l + 1) * (r - l + 2) / 2; i++) {
    string tmp;
    cin >> tmp;
    sort(tmp.begin(), tmp.end());
    ret[id].push_back(tmp);
  }
}
void recover_half() {
  sort(ret[0].begin(), ret[0].end(),
       [](string x, string y) { return x.length() < y.length(); });
  sort(ret[1].begin(), ret[1].end(),
       [](string x, string y) { return x.length() < y.length(); });
  vector<bool> used((int)ret[1].size(), false);
  for (auto x : ret[0]) {
    bool f = false;
    int id = 0;
    for (auto y : ret[1]) {
      if (y == x && !used[id]) {
        f = true;
        used[id] = true;
        break;
      }
      ++id;
    }
    if (f) continue;
    int tmp[26] = {0};
    int len = x.length();
    for (auto z : x) tmp[z - 'a']++;
    for (int i = 1; i < len; i++) tmp[ans[i] - 'a']--;
    for (int i = 0; i < 26; i++)
      if (tmp[i]) ans[len] = i + 'a';
  }
}
void recover_final() {
  for (auto x : ret[2]) {
    int len = x.length();
    for (auto y : x) {
      cnt[len][y - 'a']++;
    }
  }
  for (int i = n / 2; i >= 1; i--) {
    int tmp[26] = {0};
    for (int j = 0; j < 26; j++) tmp[j] = cnt[i][j] - cnt[i - 1][j];
    for (int j = i; j <= n - i; j++) tmp[ans[j] - 'a']--;
    for (int j = 0; j < 26; j++)
      if (tmp[j]) ans[n - i + 1] = j + 'a';
  }
}
int main() {
  int i, j;
  scanf("%d", &n);
  ask(0, 1, (n + 1) / 2);
  ask(1, 2, (n + 1) / 2);
  ask(2, 1, n);
  if (n == 1) {
    printf("! %s\n", ret[0][0].c_str());
  } else {
    ans[n + 1] = 0;
    recover_half();
    recover_final();
    printf("! %s\n", ans + 1);
  }
  return 0;
}
