#include <bits/stdc++.h>
using namespace std;
const long long MOD = 1e9 + 7;
const long long LLINF = 1e18 + 7;
void fl() { cout.flush(); }
void ask(int l, int r) {
  cout << "? " << l << " " << r << '\n';
  fl();
}
string read() {
  string s;
  cin >> s;
  sort(s.begin(), s.end());
  return s;
}
bool cmp(string &s, string &t) { return s.size() < t.size(); }
multiset<string> secik;
char extract(string &s, string &t) {
  int tab['z' - 'a' + 1];
  for (int i = 0; i < 'z' - 'a' + 1; i++) {
    tab[i] = 0;
  }
  for (int i = 0; i < s.size(); i++) {
    tab[s[i] - 'a']++;
  }
  for (int i = 0; i < t.size(); i++) {
    tab[t[i] - 'a']--;
  }
  for (int i = 0; i < 'z' - 'a' + 1; i++) {
    if (tab[i] > 0) {
      return (char)(i + 'a');
    }
  }
  return 0;
}
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);
  ;
  int n;
  cin >> n;
  if (n == 1) {
    ask(1, 1);
    string s;
    cin >> s;
    fl();
    cout << "! " << s << '\n';
    fl();
    return 0;
  }
  ask(1, n);
  for (int i = 0; i < (n + 1) * n / 2; i++) {
    secik.insert(read());
  }
  ask(2, n);
  for (int i = 0; i < n * (n - 1) / 2; i++) {
    secik.erase(secik.find(read()));
  }
  vector<string> vec;
  for (auto el : secik) {
    vec.push_back(el);
  }
  vec.push_back("");
  sort(vec.begin(), vec.end(), cmp);
  string ans = "";
  for (int i = 1; i < vec.size(); i++) {
    ans += extract(vec[i], vec[i - 1]);
  }
  cout << "! " << ans << '\n';
  fl();
}
