#include <bits/stdc++.h>
using namespace std;
int tot(int n) { return n * (n + 1) / 2; }
vector<pair<char, char> > candidates(int n) {
  cout << "? " << 1 << " " << n << endl;
  cout.flush();
  int k = tot(n);
  vector<string> s;
  vector<vector<string> > len;
  len.resize(n + 1);
  for (int i = 0; i < k; ++i) {
    string cur;
    cin >> cur;
    s.push_back(cur);
    len[cur.length()].push_back(cur);
  }
  vector<pair<char, char> > identified;
  string full = len[n][0];
  int step = 0;
  for (int i = n - 1; step < n / 2; --i) {
    ++step;
    int mult = (n - i) + 1;
    vector<int> cntideal(26, 0);
    for (int j = 0; j < n; ++j) {
      ++cntideal[len[n][0][j] - 'a'];
    }
    for (int j = 0; j < 26; ++j) {
      cntideal[j] *= mult;
    }
    for (auto x : len[i]) {
      for (int j = 0; j < x.length(); ++j) {
        --cntideal[x[j] - 'a'];
      }
    }
    int cntin = mult - 1;
    for (auto p : identified) {
      cntideal[p.first - 'a'] -= cntin;
      cntideal[p.second - 'a'] -= cntin;
      --cntin;
    }
    string s;
    for (int j = 0; j < 26; ++j) {
      if (cntideal[j] > 0) {
        s += (char)('a' + j);
      }
    }
    if (s.length() == 1) {
      identified.push_back(make_pair(s[0], s[0]));
    } else {
      identified.push_back(make_pair(s[0], s[1]));
    }
  }
  multiset<char> have(full.begin(), full.end());
  for (int i = 0; i < identified.size(); ++i) {
    have.erase(have.find(identified[i].first));
    have.erase(have.find(identified[i].second));
  }
  if (!have.empty()) {
    identified.push_back(make_pair(*have.begin(), *have.begin()));
  }
  return identified;
}
string solve_many(int n) {
  multiset<string> s;
  cout << "? " << 1 << " " << n << endl;
  cout.flush();
  int k = tot(n);
  for (int i = 0; i < k; ++i) {
    string cur;
    cin >> cur;
    sort(cur.begin(), cur.end());
    s.insert(cur);
  }
  if (n == 1) {
    return *s.begin();
  }
  cout << "? " << 2 << " " << n << endl;
  cout.flush();
  int ck = tot(n - 1);
  for (int i = 0; i < ck; ++i) {
    string cur;
    cin >> cur;
    sort(cur.begin(), cur.end());
    s.erase(s.find(cur));
  }
  string result = "";
  for (int i = 1; i <= n; ++i) {
    string v;
    for (auto x : s) {
      if (x.length() == i) {
        v = x;
        break;
      }
    }
    multiset<char> cur;
    for (int j = 0; j < v.size(); ++j) {
      cur.insert(v[j]);
    }
    for (int j = 0; j < result.size(); ++j) {
      cur.erase(cur.find(result[j]));
    }
    result += *cur.begin();
  }
  return result;
}
void solve() {
  int n;
  cin >> n;
  if (n == 1) {
    cout << "? 1 1" << endl;
    string s;
    cin >> s;
    cout << "! " << s << endl;
    return;
  }
  auto identified = candidates(n);
  string half = solve_many(n / 2);
  string ans;
  for (int i = 0; i < n; ++i) {
    ans += ' ';
  }
  for (int i = 0; i < half.size(); ++i) {
    ans[i] = half[i];
    if (identified[i].first == ans[i]) {
      ans[n - i - 1] = identified[i].second;
    } else {
      ans[n - i - 1] = identified[i].first;
    }
  }
  if (n % 2 == 1) {
    ans[n / 2] = identified[n / 2].first;
  }
  cout << "! " << ans << endl;
  cout.flush();
}
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  int t;
  t = 1;
  for (int tt = 0; tt < t; ++tt) {
    solve();
  }
  return 0;
}
