#include<bits/stdc++.h>
#define LL long long
#define pb push_back
#define mp make_pair
#define pii pair<int,int>
using namespace std;
inline int read(){
	int v=0,f=1;
	char c=getchar();
	while (c<'0' || c>'9'){
		if (c=='-') f=-1;
		c=getchar();
	}
	while (c>='0' && c<='9'){
		v=v*10+c-'0';
		c=getchar();
	}
	return v*f;
}
const int Maxn=105;
int cnt[Maxn][26];
int S1[Maxn],S2[Maxn],S3[Maxn];
char tmp[Maxn];
void Query(int l,int r){
	printf("? %d %d\n",l,r);
	fflush(stdout);
	memset(cnt,0,sizeof(cnt));
	int c=(r-l+1)*(r-l+2)/2;
	for (int i=0;i<c;i++){
		scanf("%s",tmp);
		int l=strlen(tmp);
		for (int j=0;j<l;j++){
			cnt[l][tmp[j]-'a']++;
		}
	}
}
int ans[Maxn];
vector<pair<int,int> > G[Maxn];
bool vis[Maxn];
int main(){
	int n;
	scanf("%d",&n);
	int l=1,r=n,mid=l+r>>1;
	vector<int> V;
	if (mid-l==r-mid){
		Query(1,n);
		int T=(n+1)/2;
		for (int i=T;i>=1;i--){
			for (int j=0;j<26;j++){
				S1[i]+=cnt[i][j]*j;
				S1[i]-=cnt[i-1][j]*j;
			}
			for (int j=i+1;j<=T;j++){
				S1[i]-=S1[j];
			}
		}
		for (int i=1;i<=T;i++){
			int x=i,y=n+1-i;
			if (x==y){
				ans[x]=S1[i];
				V.pb(x);
			}
			else{
				G[x].pb(mp(y,S1[i]));
				G[y].pb(mp(x,S1[i]));
			}
		}
		Query(1,mid-1);
		T=mid/2;
		for (int i=T;i>=1;i--){
			for (int j=0;j<26;j++){
				S2[i]+=cnt[i][j]*j;
				S2[i]-=cnt[i-1][j]*j;
			}
			for (int j=i+1;j<=T;j++){
				S2[i]-=S2[j];
			}
		}
		for (int i=1;i<=T;i++){
			int x=i,y=mid-i;
			if (x==y){
				ans[x]=S2[i];
				V.pb(x);
			}
			else{
				G[x].pb(mp(y,S2[i]));
				G[y].pb(mp(x,S2[i]));
			}
		}
		Query(mid,n);
		T=(n-mid+2)/2;
		for (int i=T;i>=1;i--){
			for (int j=0;j<26;j++){
				S3[i]+=cnt[i][j]*j;
				S3[i]-=cnt[i-1][j]*j;
			}
			for (int j=i+1;j<=T;j++){
				S3[i]-=S3[j];
			}
		}
		for (int i=1;i<=T;i++){
			int x=i+mid-1,y=mid+n-x;
			if (x==y){
				ans[x]=S3[i];
				V.pb(x);
			}
			else{
				G[x].pb(mp(y,S3[i]));
				G[y].pb(mp(x,S3[i]));
			}
		}
		while (!V.empty()){
			int x=V.back();V.pop_back();
			if (vis[x]) continue;
			vis[x]=true;
			for (int i=0;i<G[x].size();i++){
				int A=G[x][i].first,S=G[x][i].second;
				ans[A]=S-ans[x];
				V.pb(A);
			}
		}
		printf("! ");
		for (int i=1;i<=n;i++){
			putchar(ans[i]+'a');
		}
		printf("\n");
		fflush(stdout);
		return 0;
	}

	Query(1,n);
	int T=(n+1)/2;
	for (int i=T;i>=1;i--){
		for (int j=0;j<26;j++){
			S1[i]+=cnt[i][j]*j;
			S1[i]-=cnt[i-1][j]*j;
		}
		for (int j=i+1;j<=T;j++){
			S1[i]-=S1[j];
		}
	}
	for (int i=1;i<=T;i++){
		int x=i,y=n+1-i;
		if (x==y){
			ans[x]=S1[i];
			V.pb(x);
		}
		else{
			G[x].pb(mp(y,S1[i]));
			G[y].pb(mp(x,S1[i]));
		}
	}
	Query(1,mid);
	T=(mid+1)/2;
	for (int i=T;i>=1;i--){
		for (int j=0;j<26;j++){
			S2[i]+=cnt[i][j]*j;
			S2[i]-=cnt[i-1][j]*j;
		}
		for (int j=i+1;j<=T;j++){
			S2[i]-=S2[j];
		}
	}
	for (int i=1;i<=T;i++){
		int x=i,y=mid+1-i;
		if (x==y){
			ans[x]=S2[i];
			V.pb(x);
		}
		else{
			G[x].pb(mp(y,S2[i]));
			G[y].pb(mp(x,S2[i]));
		}
	}
	Query(mid,n);
	T=(n-mid+2)/2;
	for (int i=T;i>=1;i--){
		for (int j=0;j<26;j++){
			S3[i]+=cnt[i][j]*j;
			S3[i]-=cnt[i-1][j]*j;
		}
		for (int j=i+1;j<=T;j++){
			S3[i]-=S3[j];
		}
	}
	for (int i=1;i<=T;i++){
		int x=i+mid-1,y=mid+n-x;
		if (x==y){
			ans[x]=S3[i];
			V.pb(x);
		}
		else{
			G[x].pb(mp(y,S3[i]));
			G[y].pb(mp(x,S3[i]));
		}
	}
	while (!V.empty()){
		int x=V.back();V.pop_back();
		if (vis[x]) continue;
		vis[x]=true;
		for (int i=0;i<G[x].size();i++){
			int A=G[x][i].first,S=G[x][i].second;
			ans[A]=S-ans[x];
			V.pb(A);
		}
	}
	printf("! ");
	for (int i=1;i<=n;i++){
		putchar(ans[i]+'a');
	}
	printf("\n");
	fflush(stdout);
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define all(v) (v).begin(), (v).end()
#define sz(v) (int)(v).size()

typedef long long ll;

struct Edge
{
    int i, j;
    char x, y;

    Edge(int _i, int _j, char _x, char _y): i(_i), j(_j), x(_x), y(_y) {};
    Edge() {};

    void print() {
        cout << i << ' ' << j << ' ' << x << ' ' << y << '\n';
    }
};

const int N = 101;

vector<Edge> edges;
vector<int> gr[N];

int cnt[26][N];
char s[N];

void addEdge(int i, int j, char x, char y)
{
    gr[i].push_back(sz(edges));
    gr[j].push_back(sz(edges));
    edges.push_back(Edge(i, j, x, y));
}

void get(int l, int r)
{
    cout << "? " << l + 1 << ' ' << r + 1 << '\n';
    cout.flush();
    int n = r - l + 1;
    int inp = n * (n + 1) / 2;

    for (int c = 0; c < 26; ++c)
        for (int i = 1; i <= n; ++i)
            cnt[c][i] = 0;

    while(inp--) {
        string t;
        cin >> t;
        for (char ch : t)
            ++cnt[ch - 'a'][sz(t)];
    }

    for (int k = 2; k <= (n + 1) / 2; ++k) {
        char pr[2];
        int pos = 0;
        for (int c = 0; c < 26; ++c) {
            cnt[c][k] = k * cnt[c][1] - cnt[c][k];
            cnt[c][1] -= cnt[c][k];
            for (int i = k + 1; i <= n; ++i)
                cnt[c][i] -= (k - 1) * cnt[c][k];
            while(cnt[c][k]--)
                pr[pos++] = char('a' + c);
        }
        addEdge(l, r, pr[0], pr[1]);
        ++l; --r;
    }

    if (n & 1) {
        for (int c = 0; c < 26; ++c)
            if (cnt[c][1])
                s[l] = char('a' + c);
    } else {
        char pr[2];
        int pos = 0;
        for (int c = 0; c < 26; ++c) {
            while(cnt[c][1]--)
                pr[pos++] = char('a' + c);
        }
        addEdge(l, r, pr[0], pr[1]);
    }

}

bool used[N];

void dfs(int v)
{
    //cout << v << ' ' << s[v] << '\n';
    used[v] = true;
    for (int i : gr[v]) {
        Edge& e = edges[i];
        int u = e.i ^ e.j ^ v;
        if (!used[u]) {
            s[u] = s[v] ^ e.x ^ e.y;
            dfs(u);
        }
    }
}

void ans(int n)
{
    cout << "! ";
    for (int i = 0; i < n; ++i)
        cout << s[i];
    exit(0);
}

int main()
{
    int n;
    cin >> n;

    if (n == 1) {
        get(0, 0);
        ans(1);
    }
    if (n == 2) {
        get(0, 0);
        get(1, 1);
        ans(2);
    }

    get(0, n - 1);
    int m = n / 2;
    if (n & 1) {
        get(0, m - 1);
        get(m, n - 1);
    } else {
        get(0, m);
        get(m, n - 1);
        Edge& e1 = edges[gr[0].back()];
        Edge& e2 = edges[gr[n - 1].back()];
        Edge& e3 = edges[gr[0][0]];

        /*
        cout << "<--------------->\n";
        e1.print();
        e2.print();
        e3.print();
        cout << "<--------------->\n";
        */

        map<char,int> cur;
        ++cur[e1.x]; ++cur[e1.y];
        ++cur[e2.x]; ++cur[e2.y];
        --cur[e3.x]; --cur[e3.y];

        for (auto pr : cur) {
            //cout << pr.first << ' ' << pr.second << ' ' << m << '\n';
            if (pr.second) s[m] = pr.first;
        }
    }

    /*
    for (Edge& e : edges)
        e.print();
    cout << '\n';
    */

    dfs(m);
    ans(n);
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
#define mp make_pair
#define PI pair<int,int>
#define poly vector<ll>
#define mem(a) memset((a),0,sizeof(a))
#define For(i,l,r) for(int i=(int)(l);i<=(int)(r);i++)
#define Rep(i,r,l) for(int i=(int)(r);i>=(int)(l);i--)
#define pb push_back
#define fi first
#define se second
inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline ll read(){
	ll x = 0; char ch = gc(); bool positive = 1;
	for (; !isdigit(ch); ch = gc())	if (ch == '-')	positive = 0;
	for (; isdigit(ch); ch = gc())	x = x * 10 + ch - '0';
	return positive ? x : -x;
}
inline void write(ll a){
    if(a<0){
    	a=-a; putchar('-');
	}
    if(a>=10)write(a/10);
    putchar('0'+a%10);
}
inline void writeln(ll a){write(a); puts("");}
inline void wri(ll a){write(a); putchar(' ');}
inline ull rnd(){
	return ((ull)rand()<<30^rand())<<4|rand()%4;
}
const int N=105;
int to[N<<1];
multiset<string> A[N],B[N],C[N];
char ch[N];
void Read(multiset<string> a[N],int l,int r){
	cout<<"? "<<l<<" "<<r<<endl;
	int cnt=(r-l+2)*(r-l+1)/2;
	For(i,1,cnt){
		string s;
		cin>>s; sort(s.begin(),s.end());
		a[s.length()].insert(s);
	}
}
int main(){
	int n=read();
	if(n<=3){
		string ans,s;
		For(i,1,n){
			cout<<"? "<<i<<" "<<i<<endl;
			cin>>s;
			ans+=s;
		}
		cout<<"! "<<ans<<endl;
		return 0;
	}
	Read(A,1,n);
	int len=(n+1)/2;
	Read(B,1,len);
	Read(C,1,len-1);
	For(i,1,len){
		string ans;
		for(auto j:B[i])if(C[i].find(j)!=C[i].end())C[i].erase(C[i].find(j)); else ans=j;
		int sum=0;
		for(auto j:ans)sum^=j;
		For(j,len-i+2,len)sum^=ch[j];
		ch[len-i+1]=sum;
	}
	For(i,2,n-len+1){
		mem(to);
		for(auto j:A[i])for(auto k:j)to[k]++;
		for(auto j:B[i])for(auto k:j)to[k]--;
		Rep(j,len,len-i+2)to[ch[j]]-=i-(len-j+1);
		For(j,n-i+3,n)to[ch[j]]-=n-j+1;
		For(j,'a','z'){
			if(to[j]%i)ch[n-i+2]=j;
			to[j]=0;
		}
	}
	cout<<"! "<<ch+1<<endl;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
#define mp make_pair
#define PI pair<int,int>
#define poly vector<ll>
#define mem(a) memset((a),0,sizeof(a))
#define For(i,l,r) for(int i=(int)(l);i<=(int)(r);i++)
#define Rep(i,r,l) for(int i=(int)(r);i>=(int)(l);i--)
#define pb push_back
#define fi first
#define se second
inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline ll read(){
	ll x = 0; char ch = gc(); bool positive = 1;
	for (; !isdigit(ch); ch = gc())	if (ch == '-')	positive = 0;
	for (; isdigit(ch); ch = gc())	x = x * 10 + ch - '0';
	return positive ? x : -x;
}
inline void write(ll a){
    if(a<0){
    	a=-a; putchar('-');
	}
    if(a>=10)write(a/10);
    putchar('0'+a%10);
}
inline void writeln(ll a){write(a); puts("");}
inline void wri(ll a){write(a); putchar(' ');}
inline ull rnd(){
	return ((ull)rand()<<30^rand())<<4|rand()%4;
}
const int N=105;
int to[N<<1];
multiset<string> A[N],B[N],C[N];
char ch[N];
void Read(multiset<string> a[N],int l,int r){
	cout<<"? "<<l<<" "<<r<<endl;
	int cnt=(r-l+2)*(r-l+1)/2;
	For(i,1,cnt){
		string s;
		cin>>s;
		a[s.length()].insert(s);
	}
}
int main(){
	int n=read();
	if(n<=3){
		string ans,s;
		For(i,1,n){
			cout<<"? "<<i<<" "<<i<<endl;
			cin>>s;
			ans+=s;
		}
		cout<<"! "<<ans<<endl;
		return 0;
	}
	Read(A,1,n);
	int len=(n+1)/2;
	Read(B,1,len);
	Read(C,1,len-1);
	For(i,1,len){
		string ans;
		for(auto j:B[i])if(C[i].find(j)!=C[i].end())C[i].erase(C[i].find(j)); else ans=j;
		int sum=0;
		for(auto j:ans)sum^=j;
		For(j,len-i+2,len)sum^=ch[j];
		ch[len-i+1]=sum;
	}
	For(i,2,n-len+1){
		mem(to);
		for(auto j:A[i])for(auto k:j)to[k]++;
		for(auto j:B[i])for(auto k:j)to[k]--;
		Rep(j,len,len-i+2)to[ch[j]]-=i-(len-j+1);
		For(j,n-i+3,n)to[ch[j]]-=n-j+1;
		For(j,'a','z'){
			if(to[j]%i)ch[n-i+2]=j;
			to[j]=0;
		}
	}
	cout<<"! "<<ch+1<<endl;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
#define mp make_pair
#define PI pair<int,int>
#define poly vector<ll>
#define mem(a) memset((a),0,sizeof(a))
#define For(i,l,r) for(int i=(int)(l);i<=(int)(r);i++)
#define Rep(i,r,l) for(int i=(int)(r);i>=(int)(l);i--)
#define pb push_back
#define fi first
#define se second
inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline ll read(){
	ll x = 0; char ch = gc(); bool positive = 1;
	for (; !isdigit(ch); ch = gc())	if (ch == '-')	positive = 0;
	for (; isdigit(ch); ch = gc())	x = x * 10 + ch - '0';
	return positive ? x : -x;
}
inline void write(ll a){
    if(a<0){
    	a=-a; putchar('-');
	}
    if(a>=10)write(a/10);
    putchar('0'+a%10);
}
inline void writeln(ll a){write(a); puts("");}
inline void wri(ll a){write(a); putchar(' ');}
inline ull rnd(){
	return ((ull)rand()<<30^rand())<<4|rand()%4;
}
const int N=105;
int to[N<<1];
vector<string> A[N],B[N],C[N];
char ch[N];
void Read(vector<string> a[N],int l,int r){
	cout<<"? "<<l<<" "<<r<<endl;
	int cnt=(r-l+2)*(r-l+1)/2;
	For(i,1,cnt){
		string s;
		cin>>s;
		a[s.length()].pb(s);
	}
}
int main(){
	int n=read();
	if(n<=3){
		string ans,s;
		For(i,1,n){
			cout<<"? "<<i<<" "<<i<<endl;
			cin>>s;
			ans+=s;
		}
		cout<<"! "<<ans<<endl;
		return 0;
	}
	Read(A,1,n);
	int len=(n+1)/2; //len=n;
	Read(B,1,len);
	Read(C,1,len-1);
	For(i,1,len){
		string ans;
		int sum=0;
		for(auto j:B[i])for(auto k:j)sum^=k;
		for(auto j:C[i])for(auto k:j)sum^=k;
		For(j,len-i+2,len)sum^=ch[j];
		ch[len-i+1]=sum;
	}
	For(i,2,n-len+1){
		mem(to);
		for(auto j:A[i])for(auto k:j)to[k]++;
		for(auto j:B[i])for(auto k:j)to[k]--;
		Rep(j,len,len-i+2)to[ch[j]]-=i-(len-j+1);
		For(j,n-i+3,n)to[ch[j]]-=n-j+1;
		For(j,'a','z'){
			if(to[j]%i)ch[n-i+2]=j;
			to[j]=0;
		}
	}
	cout<<"! "<<ch+1<<endl;
}
/*
*/


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
#define mp make_pair
#define PI pair<int,int>
#define poly vector<ll>
#define mem(a) memset((a),0,sizeof(a))
#define For(i,l,r) for(int i=(int)(l);i<=(int)(r);i++)
#define Rep(i,r,l) for(int i=(int)(r);i>=(int)(l);i--)
#define pb push_back
#define fi first
#define se second
inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline ll read(){
	ll x = 0; char ch = gc(); bool positive = 1;
	for (; !isdigit(ch); ch = gc())	if (ch == '-')	positive = 0;
	for (; isdigit(ch); ch = gc())	x = x * 10 + ch - '0';
	return positive ? x : -x;
}
inline void write(ll a){
    if(a<0){
    	a=-a; putchar('-');
	}
    if(a>=10)write(a/10);
    putchar('0'+a%10);
}
inline void writeln(ll a){write(a); puts("");}
inline void wri(ll a){write(a); putchar(' ');}
inline ull rnd(){
	return ((ull)rand()<<30^rand())<<4|rand()%4;
}
const int N=105;
int to[N<<1];
multiset<string> A[N],B[N],C[N];
char ch[N];
void Read(multiset<string> a[N],int l,int r){
	cout<<"? "<<l<<" "<<r<<endl;
	int cnt=(r-l+2)*(r-l+1)/2;
	For(i,1,cnt){
		string s;
		cin>>s;
		a[s.length()].insert(s);
	}
}
int main(){
	int n=read();
	if(n<=3){
		string ans,s;
		For(i,1,n){
			cout<<"? "<<i<<" "<<i<<endl;
			cin>>s;
			ans+=s;
		}
		cout<<"! "<<ans<<endl;
		return 0;
	}
	Read(A,1,n);
	int len=(n+1)/2;
	Read(B,1,len);
	Read(C,1,len-1);
	For(i,1,len){
		string ans;
		for(auto j:B[i])if(C[i].find(j)!=C[i].end())C[i].erase(j); else ans=j;
		int sum=0;
		for(auto j:ans)sum^=j;
		For(j,len-i+2,len)sum^=ch[j];
		ch[len-i+1]=sum;
	}
	For(i,2,n-len+1){
		mem(to);
		for(auto j:A[i])for(auto k:j)to[k]++;
		for(auto j:B[i])for(auto k:j)to[k]--;
		Rep(j,len,len-i+2)to[ch[j]]-=i-(len-j+1);
		For(j,n-i+2,n)to[ch[j]]-=n-j+1;
		For(j,'a','z'){
			if(to[j]%i)ch[n-i+2]=j;
			to[j]=0;
		}
	}
	cout<<"! "<<ch+1<<endl;
}


#include<bits/stdc++.h>
using namespace std;
const int maxn = 105;
map<string,int> H1[maxn],H2[maxn];
vector<char>ans;
char getA(string a,string b){
    int c[30];
    for(int i=0;i<26;i++)c[i]=0;
    for(int i=0;i<a.size();i++)c[a[i]-'a']++;
    for(int i=0;i<b.size();i++)c[b[i]-'a']--;
    for(int i=0;i<26;i++){
        if(c[i]>0)return i+'a';
    }
    return 'a';
}
string solve(int n){
    cout<<"? 1 "<<n<<endl;
    for(int i=0;i<n*(n+1)/2;i++){
        string s;cin>>s;
        sort(s.begin(),s.end());
        H1[s.size()][s]++;
    }
    cout<<"? 2 "<<n<<endl;
    for(int i=0;i<n*(n-1)/2;i++){
        string s;cin>>s;
        sort(s.begin(),s.end());
        H2[s.size()][s]++;
    }
    for(int i=1;i<=n;i++){
        for(auto p:H2[i]){
            H1[i][p.first]-=H2[i][p.first];
        }
        for(auto p:H1[i]){
            if(p.second>0){
                string new1="";
                for(int j=0;j<ans.size();j++)new1+=ans[j];
                ans.push_back(getA(p.first,new1));
            }
        }
    }
    string new1="";
    for(int j=0;j<ans.size();j++)new1+=ans[j];
    return new1;
    // cout<<"! "<<new1<<endl;
}
int ori[26][105];
int main(){
    int n;
    cin>>n;
    if(n==1){
        cout<<"? 1 1"<<endl;
        string sss;
        cin>>sss;
        cout<<"! "<<sss<<endl;
    }else if(n==2){
        cout<<"? 1 1"<<endl;
        string sss1,sss2;
        cin>>sss1;
        cout<<"? 2 2"<<endl;
        cin>>sss2;
        cout<<"! "<<sss1<<sss2<<endl;
    }else{
        string halfans = solve((n+1)/2);
        cout<<"? 1 "<<n<<endl;
        for(int i=0;i<n*(n+1)/2;i++){
            string sss;cin>>sss;
            for(int j=0;j<sss.size();j++){
                ori[sss[j]-'a'][sss.size()]++;
            }
        }
        string halfans2="";
        for(int i=1;i<=n/2;i++){
            for(int j=0;j<26;j++){
                int num = ori[j][1]-(ori[j][i+1]-ori[j][i]);
                for(int k=0;k<i;k++){
                    if(halfans[k]-'a'==j){
                        num--;
                    }
                }
                for(int k=0;k<halfans2.size();k++){
                    if(halfans2[k]-'a'==j){
                        num--;
                    }
                }
                if(num>0){
                    halfans2+=('a'+j);
                    break;
                }
            }
        }
        for(int i=0;i<halfans2.size();i++){
            halfans+=halfans2[halfans2.size()-1-i];
        }
        cout<<"! "<<halfans<<endl;
    }
}


#include<bits/stdc++.h>
using namespace std;
const int maxn = 105;
map<string,int> H1[maxn],H2[maxn];
vector<char>ans;
char getA(string a,string b){
    int c[30];
    for(int i=0;i<26;i++)c[i]=0;
    for(int i=0;i<a.size();i++)c[a[i]-'a']++;
    for(int i=0;i<b.size();i++)c[b[i]-'a']--;
    for(int i=0;i<26;i++){
        if(c[i]>0)return i+'a';
    }
}
int main(){
    int n;
    cin>>n;
    if(n==1){
        cout<<"? 1 1"<<endl;
        string sss;
        cin>>sss;
        cout<<"! "<<sss<<endl;
    }else{
        cout<<"? 1 "<<n<<endl;
        for(int i=0;i<n*(n+1)/2;i++){
            string s;cin>>s;
            sort(s.begin(),s.end());
            H1[s.size()][s]++;
        }
        cout<<"? 2 "<<n<<endl;
        for(int i=0;i<n*(n-1)/2;i++){
            string s;cin>>s;
            sort(s.begin(),s.end());
            H2[s.size()][s]++;
        }
        for(int i=1;i<=n;i++){
            for(auto p:H2[i]){
                H1[i][p.first]-=H2[i][p.first];
            }
            for(auto p:H1[i]){
                if(p.second>0){
                    string new1="";
                    for(int j=0;j<ans.size();j++)new1+=ans[j];
                    ans.push_back(getA(p.first,new1));
                }
            }
        }
        string new1="";
        for(int j=0;j<ans.size();j++)new1+=ans[j];
        cout<<"! "<<new1<<endl;
    }
}


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <string>
#include <algorithm>
#define llint long long
#define inf 1e18

using namespace std;
typedef pair<llint, llint> P;

struct Trie{
	struct TrieNode{
		int num, next[26];
		TrieNode(){
			num = 0;
			for(int i = 0; i < 26; i++) next[i] = -1;
		}
	};
	vector<TrieNode> vec;
	Trie(){
		init();
	}
	init(){
		vec.clear();
		vec.push_back(TrieNode());
	}
	int seek(string &s)
	{
		int p = 0;
		for(int i = 0; i < s.size(); i++){
			int c = s[i]-'a';
			if(vec[p].next[c] == -1){
				vec.push_back(TrieNode());
				vec[p].next[c] = (int)vec.size()-1;
			}
			p = vec[p].next[c];
		}
		return p;
	}
	void insert(string &s, int x = 1)
	{
		int p = seek(s);
		vec[p].num += x;
	}
	void erase(string &s, int x = 1)
	{
		int p = seek(s);
		vec[p].num = max(0, vec[p].num - x);
	}
	int count(string &s)
	{
		int p = seek(s);
		return vec[p].num;
	}
};

llint n;
Trie trie;
string str[105];
llint cnt[105][26], dif[105][26];

void get(llint cnt[], string &s)
{
	for(int i = 0; i < 26; i++) cnt[i] = 0;
	for(int i = 0; i < s.size(); i++) cnt[s[i]-'a']++;
}
void getdif(llint a[], llint b[], llint c[])
{
	for(int i = 0; i < 26; i++) c[i] = a[i] - b[i];
}

string S;
void dfs(int v, vector<string> &vec)
{
	for(int i = 0; i < trie.vec[v].num; i++) vec.push_back(S);
	for(int i = 0; i < 26; i++){
		if(trie.vec[v].next[i] != -1){
			S += (char)(i+'a');
			dfs(trie.vec[v].next[i], vec);
			S.erase(S.end()-1);
		}
	}
}

int main(void)
{
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> n;

	string s;
	if(n == 1){
		cout << "? 1 1" << endl;
		cin >> s;
		cout << "! " << s << endl;
		return 0;
	}
	llint m = n/2;

	cout << "? " << 1 << " " << m << endl;
	for(int i = 0; i < m*(m+1)/2; i++){
		cin >> s;
		sort(s.begin(), s.end());
		trie.insert(s);
	}
	if(m >= 2){
		cout << "? " << 1 << " " << m-1 << endl;
		for(int i = 0; i < m*(m-1)/2; i++){
			cin >> s;
			sort(s.begin(), s.end());
			trie.erase(s);
		}
	}

	vector<string> tmp;
	dfs(0, tmp);
	for(int i = 0; i < tmp.size(); i++) str[tmp[i].size()] = tmp[i];

	string ans = str[1];
	for(int i = 1; i < m; i++){
		llint a[26], b[26];
		get(a, str[i]), get(b, str[i+1]);
		for(int j = 0; j < 26; j++){
			if(a[j] != b[j]){
				ans += (char)(j+'a');
				break;
			}
		}
	}
	reverse(ans.begin(), ans.end());

	cout << "? " << 1 << " " << n << endl;
	for(int i = 0; i < n*(n+1)/2; i++){
		cin >> s;
		for(int j = 0; j < s.size(); j++){
			cnt[(int)s.size()][s[j]-'a']++;
		}
	}

	for(int i = 0; i <= n/2; i++) getdif(cnt[i+1], cnt[i], dif[i]);
	if(n%2){
		for(int i = 0; i < 26; i++){
			if(dif[n/2][i] > 0) ans += (char)(i+'a');
		}
	}
	/*for(int i = 0; i <= n/2; i++){
		for(int j = 0; j < 26; j++) cout << dif[i][j] << " "; cout << endl;
	}*/
	for(int i = n/2; i >= 1; i--){
		llint d[26];
		getdif(dif[i-1], dif[i], d);
		d[ans[i-1]-'a']--;
		for(int i = 0; i < 26; i++){
			if(d[i] > 0) ans += (char)(i+'a');
		}
	}
	cout << "! " << ans << endl;

	return 0;
}


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <string>
#include <algorithm>
#define llint long long
#define inf 1e18

using namespace std;
typedef pair<llint, llint> P;

struct Trie{
	struct TrieNode{
		int num, next[26];
		TrieNode(){
			num = 0;
			for(int i = 0; i < 26; i++) next[i] = -1;
		}
	};
	vector<TrieNode> vec;
	Trie(){
		init();
	}
	init(){
		vec.clear();
		vec.push_back(TrieNode());
	}
	void insert(string &s, int x = 1)
	{
		int p = 0;
		for(int i = 0; i < s.size(); i++){
			int c = s[i]-'a';
			if(vec[p].next[c] == -1){
				vec.push_back(TrieNode());
				vec[p].next[c] = (int)vec.size()-1;
			}
			p = vec[p].next[c];
		}
		vec[p].num += x;
	}
	void erase(string &s, int x = 1)
	{
		int p = 0;
		for(int i = 0; i < s.size(); i++){
			int c = s[i]-'a';
			if(vec[p].next[c] == -1) return;
			p = vec[p].next[c];
		}
		vec[p].num = max(0, vec[p].num - x);
	}
	int count(string &s)
	{
		int p = 0;
		for(int i = 0; i < s.size(); i++){
			int c = s[i]-'a';
  			if(vec[p].next[c] == -1) return 0;
			p = vec[p].next[c];
		}
		return vec[p].num;
	}
};

llint n;
Trie trie;
string str[105];
llint cnt[105][26], dif[105][26];

void get(llint cnt[], string &s)
{
	for(int i = 0; i < 26; i++) cnt[i] = 0;
	for(int i = 0; i < s.size(); i++) cnt[s[i]-'a']++;
}
void getdif(llint a[], llint b[], llint c[])
{
	for(int i = 0; i < 26; i++) c[i] = a[i] - b[i];
}

string S;
void dfs(int v, vector<string> &vec)
{
	for(int i = 0; i < trie.vec[v].num; i++) vec.push_back(S);
	for(int i = 0; i < 26; i++){
		if(trie.vec[v].next[i] != -1){
			S += (char)(i+'a');
			dfs(trie.vec[v].next[i], vec);
			S.erase(S.end()-1);
		}
	}
}

int main(void)
{
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> n;

	string s;
	if(n == 1){
		cout << "? 1 1" << endl;
		cin >> s;
		cout << "! " << s << endl;
		return 0;
	}
	llint m = n/2;

	cout << "? " << 1 << " " << m << endl;
	for(int i = 0; i < m*(m+1)/2; i++){
		cin >> s;
		sort(s.begin(), s.end());
		trie.insert(s);
	}
	if(m >= 2){
		cout << "? " << 1 << " " << m-1 << endl;
		for(int i = 0; i < m*(m-1)/2; i++){
			cin >> s;
			sort(s.begin(), s.end());
			trie.erase(s);
		}
	}

	vector<string> tmp;
	dfs(0, tmp);
	for(int i = 0; i < tmp.size(); i++) str[tmp[i].size()] = tmp[i];

	string ans = str[1];
	for(int i = 1; i < m; i++){
		llint a[26], b[26];
		get(a, str[i]), get(b, str[i+1]);
		for(int j = 0; j < 26; j++){
			if(a[j] != b[j]){
				ans += (char)(j+'a');
				break;
			}
		}
	}
	reverse(ans.begin(), ans.end());

	cout << "? " << 1 << " " << n << endl;
	for(int i = 0; i < n*(n+1)/2; i++){
		cin >> s;
		for(int j = 0; j < s.size(); j++){
			cnt[(int)s.size()][s[j]-'a']++;
		}
	}

	for(int i = 0; i <= n/2; i++) getdif(cnt[i+1], cnt[i], dif[i]);
	if(n%2){
		for(int i = 0; i < 26; i++){
			if(dif[n/2][i] > 0) ans += (char)(i+'a');
		}
	}
	/*for(int i = 0; i <= n/2; i++){
		for(int j = 0; j < 26; j++) cout << dif[i][j] << " "; cout << endl;
	}*/
	for(int i = n/2; i >= 1; i--){
		llint d[26];
		getdif(dif[i-1], dif[i], d);
		d[ans[i-1]-'a']--;
		for(int i = 0; i < 26; i++){
			if(d[i] > 0) ans += (char)(i+'a');
		}
	}
	cout << "! " << ans << endl;

	return 0;
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef long double ld;
typedef double db;
typedef string str;

typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;
#define mp make_pair
#define f first
#define s second

typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<ld> vd;
typedef vector<str> vs;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<pd> vpd;

#define sz(x) (int)x.size()
#define all(x) begin(x), end(x)
#define rall(x) (x).rbegin(), (x).rend()
#define rsz resize
#define ins insert
#define ft front()
#define bk back()
#define pf push_front
#define pb push_back
#define eb emplace_back
#define lb lower_bound
#define ub upper_bound

#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define ROF(i,a,b) for (int i = (b)-1; i >= (a); --i)
#define R0F(i,a) ROF(i,0,a)
#define trav(a,x) for (auto& a: x)

const int MOD = 1e9+7; // 998244353; // = (119<<23)+1
const int MX = 2e5+5;
const ll INF = 1e18;
const ld PI = 4*atan((ld)1);
const int xd[4] = {0,1,0,-1}, yd[4] = {1,0,-1,0};

template<class T> bool ckmin(T& a, const T& b) {
	return a > b ? a = b, 1 : 0; }
template<class T> bool ckmax(T& a, const T& b) {
	return a < b ? a = b, 1 : 0; }
mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());

#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;

template <class T> using Tree = tree<T, null_type, less<T>,
	rb_tree_tag, tree_order_statistics_node_update>;
// change null_type for map
#define ook order_of_key
#define fbo find_by_order

void treeExample() {
	Tree<int> t, t2; t.insert(8);
	auto it = t.insert(10).f; assert(it == t.lb(9));
	assert(t.ook(10) == 1); assert(t.ook(11) == 2);
	assert(*t.fbo(0) == 8);
	t.join(t2); // assuming T < T2 or T > T2, merge t2 into t
}

namespace input {
	template<class T> void re(complex<T>& x);
	template<class T1, class T2> void re(pair<T1,T2>& p);
	template<class T> void re(vector<T>& a);
	template<class T, size_t SZ> void re(array<T,SZ>& a);

	template<class T> void re(T& x) { cin >> x; }
	void re(double& x) { string t; re(t); x = stod(t); }
	void re(ld& x) { string t; re(t); x = stold(t); }
	template<class T, class... Ts> void re(T& t, Ts&... ts) {
		re(t); re(ts...);
	}

	template<class T> void re(complex<T>& x) { T a,b; re(a,b); x = cd(a,b); }
	template<class T1, class T2> void re(pair<T1,T2>& p) { re(p.f,p.s); }
	template<class T> void re(vector<T>& a) { F0R(i,sz(a)) re(a[i]); }
	template<class T, size_t SZ> void re(array<T,SZ>& a) { F0R(i,SZ) re(a[i]); }
}

using namespace input;

namespace output {
	void pr(int x) { cout << x; }
	void pr(long x) { cout << x; }
	void pr(ll x) { cout << x; }
	void pr(unsigned x) { cout << x; }
	void pr(unsigned long x) { cout << x; }
	void pr(unsigned long long x) { cout << x; }
	void pr(float x) { cout << x; }
	void pr(double x) { cout << x; }
	void pr(ld x) { cout << x; }
	void pr(char x) { cout << x; }
	void pr(const char* x) { cout << x; }
	void pr(const string& x) { cout << x; }
	void pr(bool x) { pr(x ? "true" : "false"); }
	template<class T> void pr(const complex<T>& x) { cout << x; }

	template<class T1, class T2> void pr(const pair<T1,T2>& x);
	template<class T> void pr(const T& x);

	template<class T, class... Ts> void pr(const T& t, const Ts&... ts) {
		pr(t); pr(ts...);
	}
	template<class T1, class T2> void pr(const pair<T1,T2>& x) {
		pr("{",x.f,", ",x.s,"}");
	}
	template<class T> void pr(const T& x) {
		pr("{"); // const iterator needed for vector<bool>
		bool fst = 1; for (const auto& a: x) pr(!fst?", ":"",a), fst = 0;
		pr("}");
	}

	void ps() { cout << endl; } // print w/ spaces
	template<class T, class... Ts> void ps(const T& t, const Ts&... ts) {
		pr(t); if (sizeof...(ts)) pr(" "); ps(ts...);
	}

	void pc() { pr("]\n"); } // debug w/ commas
	template<class T, class... Ts> void pc(const T& t, const Ts&... ts) {
		pr(t); if (sizeof...(ts)) pr(", "); pc(ts...);
	}
	#define dbg(x...) pr("[",#x,"] = ["), pc(x);
}

using namespace output;

namespace io {
	void setIn(string s) { freopen(s.c_str(),"r",stdin); }
	void setOut(string s) { freopen(s.c_str(),"w",stdout); }
	void setIO(string s = "") {
		ios_base::sync_with_stdio(0); cin.tie(0); // fast I/O
		// cin.exceptions(cin.failbit); // ex. throws exception when you try to read letter into int
		if (sz(s)) { setIn(s+".in"), setOut(s+".out"); } // for USACO
	}
}

using namespace io;

struct mi {
	typedef decay<decltype(MOD)>::type T;
	T val;
	explicit operator T() const { return val; }
	mi() { val = 0; }
	mi(ll v) {
		val = (-MOD <= v && v <= MOD) ? v : v % MOD;
		if (val < 0) val += MOD;
	}
	friend bool operator==(const mi& a, const mi& b) {
		return a.val == b.val; }
	friend bool operator!=(const mi& a, const mi& b) {
		return !(a == b); }
	friend bool operator<(const mi& a, const mi& b) {
		return a.val < b.val; }
	friend void re(mi& a) { ll x; re(x); a = mi(x); }
	friend void pr(const mi& a) { pr(a.val); }
	friend ostream& operator<<(ostream& os, const mi& a) {
		return os << a.val; }

	mi operator-() const { return mi(-val); }
	mi& operator+=(const mi& m) {
		if ((val += m.val) >= MOD) val -= MOD;
		return *this; }
	mi& operator-=(const mi& m) {
		if ((val -= m.val) < 0) val += MOD;
		return *this; }
	mi& operator++() { return *this += 1; }
	mi& operator--() { return *this -= 1; }
	friend mi operator+(mi a, const mi& b) { return a += b; }
	friend mi operator-(mi a, const mi& b) { return a -= b; }

	mi& operator*=(const mi& m) {
		val = (ll)val*m.val%MOD; return *this; }
	friend mi pow(mi a, ll p) {
		mi ans = 1; assert(p >= 0);
		for (; p; p /= 2, a *= a) if (p&1) ans *= a;
		return ans;
	}
	friend mi inv(const mi& a) {
		assert(!(a == 0)); return pow(a,MOD-2); }
	mi& operator/=(const mi& m) { return (*this) *= inv(m); }
	friend mi operator*(mi a, const mi& b) { return a *= b; }
	friend mi operator/(mi a, const mi& b) { return a /= b; }
};
typedef pair<mi,mi> pmi;
typedef vector<mi> vmi;
typedef vector<pmi> vpmi;

str hide = "abcdefbaawerewrra";
int n;

int comb(int x) { return x*(x+1)/2; }

multiset<str> m;
str res[101];

vs query(int l, int r) {
	if (l > r) return {};
	ps("?",l,r);
	vs v(comb(r-l+1)); re(v);
	// vs v; FOR(i,l,r+1) FOR(j,i,r+1) v.pb(hide.substr(i-1,j-i+1));
	trav(t,v) sort(all(t));
	return v;
}

int dif(str a, str b) {
	multiset<char> A(all(a));
	trav(t,b) A.erase(A.find(t));
	return *begin(A);
}

void fin(str s) {
	ps("!",s);
	exit(0);
}

int cur[105];

void FIN() {
	str res;
	FOR(i,1,n+1) res += char('a'+cur[i]);
	fin(res);
}

vector<pair<int,pi>> ADJ[105];

void ae(int l, int r, int x, int y) {
	// ps("ED",l,r);
	ADJ[l].pb({r,{x,y}}), ADJ[r].pb({l,{x,y}});
}

void gen(int l, int r) {
	if (l > r) return;
	l++, r++;
	// ps("CHECK",l,r);
	auto a = query(l,r);
	vi oc[105]; F0R(i,105) oc[i].rsz(26);
	trav(t,a) {
		//ps("WUT",t);
		trav(c,t) oc[sz(t)][c-'a'] ++;
	}
	int LEN = r-l+1; int hi = LEN/2;
	// FOR(i,1,LEN+1) ps(i,oc[i]);
	for (int len = 1; len <= hi; len++) {
		vi tmp(26);
		F0R(i,26) tmp[i] = (len+1)*oc[LEN][i]-oc[LEN-len][i];
		vi cool;
		F0R(i,26) F0R(j,tmp[i]) {
			cool.pb(i);
			FOR(z,len+1,hi+1) oc[LEN-z][i] -= len;
			oc[LEN][i] --;
		}
		//ps("??",len,cool);
		assert(sz(cool) == 2);
		ae(l+len-1,r-len+1,cool[0],cool[1]);
		//ps("HA",l,r,cool);
	}
	if (LEN&1) {
		int cnt = 0;
		F0R(i,sz(oc[LEN])) F0R(j,oc[LEN][i]) {
			ae(l+LEN/2,r-LEN/2,i,i);
			cnt ++;
		}
		assert(cnt == 1);
	}
	//exit(0);
}

void tri(int a, int b) {
	if (cur[a] != -1) return;
	cur[a] = b;
	trav(t,ADJ[a]) {
		if (t.s.f == b) tri(t.f,t.s.s);
		else tri(t.f,t.s.f);
	}
}

bool ok() {
	FOR(i,1,n+1) trav(t,ADJ[i]) {
		pi p = {cur[i],cur[t.f]};
		if (p == t.s || mp(p.s,p.f) == t.s) {

		} else return 0;
	}
	return 1;
}

int main() {
	// n = sz(hide);
	re(n);
	if (n == 1) {
		auto a = query(1,1);
		fin(a[0]);
	}
	int l,r;
	if (n%4 == 1) {
		l = n/2+1, r = n/2+1;
	} else {
		l = n/2-1, r = n/2;
	}
	// 1 to 5, 6 to 9
	// ps(l,r);
	gen(0,n-1), gen(0,l-1); gen(r,n-1);
	auto a = ADJ[1][0];
	FOR(i,1,n+1) cur[i] = -1;
	tri(1,a.s.f);
	// FOR(i,1,n+1) ps(i,cur[i]);
	if (ok()) FIN();
	FOR(i,1,n+1) cur[i] = -1;
	tri(1,a.s.s);
	if (ok()) FIN();
	exit(5);
	// you should actually read the stuff at the bottom
}

/* stuff you should look for
	* int overflow, array bounds
	* special cases (n=1?), slow multiset operations
	* do smth instead of nothing and stay organized
*/


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef long double ld;
typedef double db;
typedef string str;

typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;
#define mp make_pair
#define f first
#define s second

typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<ld> vd;
typedef vector<str> vs;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<pd> vpd;

#define sz(x) (int)x.size()
#define all(x) begin(x), end(x)
#define rall(x) (x).rbegin(), (x).rend()
#define rsz resize
#define ins insert
#define ft front()
#define bk back()
#define pf push_front
#define pb push_back
#define eb emplace_back
#define lb lower_bound
#define ub upper_bound

#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define ROF(i,a,b) for (int i = (b)-1; i >= (a); --i)
#define R0F(i,a) ROF(i,0,a)
#define trav(a,x) for (auto& a: x)

const int MOD = 1e9+7; // 998244353; // = (119<<23)+1
const int MX = 2e5+5;
const ll INF = 1e18;
const ld PI = 4*atan((ld)1);
const int xd[4] = {0,1,0,-1}, yd[4] = {1,0,-1,0};

template<class T> bool ckmin(T& a, const T& b) {
	return a > b ? a = b, 1 : 0; }
template<class T> bool ckmax(T& a, const T& b) {
	return a < b ? a = b, 1 : 0; }
mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());

#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;

template <class T> using Tree = tree<T, null_type, less<T>,
	rb_tree_tag, tree_order_statistics_node_update>;
// change null_type for map
#define ook order_of_key
#define fbo find_by_order

void treeExample() {
	Tree<int> t, t2; t.insert(8);
	auto it = t.insert(10).f; assert(it == t.lb(9));
	assert(t.ook(10) == 1); assert(t.ook(11) == 2);
	assert(*t.fbo(0) == 8);
	t.join(t2); // assuming T < T2 or T > T2, merge t2 into t
}

namespace input {
	template<class T> void re(complex<T>& x);
	template<class T1, class T2> void re(pair<T1,T2>& p);
	template<class T> void re(vector<T>& a);
	template<class T, size_t SZ> void re(array<T,SZ>& a);

	template<class T> void re(T& x) { cin >> x; }
	void re(double& x) { string t; re(t); x = stod(t); }
	void re(ld& x) { string t; re(t); x = stold(t); }
	template<class T, class... Ts> void re(T& t, Ts&... ts) {
		re(t); re(ts...);
	}

	template<class T> void re(complex<T>& x) { T a,b; re(a,b); x = cd(a,b); }
	template<class T1, class T2> void re(pair<T1,T2>& p) { re(p.f,p.s); }
	template<class T> void re(vector<T>& a) { F0R(i,sz(a)) re(a[i]); }
	template<class T, size_t SZ> void re(array<T,SZ>& a) { F0R(i,SZ) re(a[i]); }
}

using namespace input;

namespace output {
	void pr(int x) { cout << x; }
	void pr(long x) { cout << x; }
	void pr(ll x) { cout << x; }
	void pr(unsigned x) { cout << x; }
	void pr(unsigned long x) { cout << x; }
	void pr(unsigned long long x) { cout << x; }
	void pr(float x) { cout << x; }
	void pr(double x) { cout << x; }
	void pr(ld x) { cout << x; }
	void pr(char x) { cout << x; }
	void pr(const char* x) { cout << x; }
	void pr(const string& x) { cout << x; }
	void pr(bool x) { pr(x ? "true" : "false"); }
	template<class T> void pr(const complex<T>& x) { cout << x; }

	template<class T1, class T2> void pr(const pair<T1,T2>& x);
	template<class T> void pr(const T& x);

	template<class T, class... Ts> void pr(const T& t, const Ts&... ts) {
		pr(t); pr(ts...);
	}
	template<class T1, class T2> void pr(const pair<T1,T2>& x) {
		pr("{",x.f,", ",x.s,"}");
	}
	template<class T> void pr(const T& x) {
		pr("{"); // const iterator needed for vector<bool>
		bool fst = 1; for (const auto& a: x) pr(!fst?", ":"",a), fst = 0;
		pr("}");
	}

	void ps() { cout << endl; } // print w/ spaces
	template<class T, class... Ts> void ps(const T& t, const Ts&... ts) {
		pr(t); if (sizeof...(ts)) pr(" "); ps(ts...);
	}

	void pc() { pr("]\n"); } // debug w/ commas
	template<class T, class... Ts> void pc(const T& t, const Ts&... ts) {
		pr(t); if (sizeof...(ts)) pr(", "); pc(ts...);
	}
	#define dbg(x...) pr("[",#x,"] = ["), pc(x);
}

using namespace output;

namespace io {
	void setIn(string s) { freopen(s.c_str(),"r",stdin); }
	void setOut(string s) { freopen(s.c_str(),"w",stdout); }
	void setIO(string s = "") {
		ios_base::sync_with_stdio(0); cin.tie(0); // fast I/O
		// cin.exceptions(cin.failbit); // ex. throws exception when you try to read letter into int
		if (sz(s)) { setIn(s+".in"), setOut(s+".out"); } // for USACO
	}
}

using namespace io;

struct mi {
	typedef decay<decltype(MOD)>::type T;
	T val;
	explicit operator T() const { return val; }
	mi() { val = 0; }
	mi(ll v) {
		val = (-MOD <= v && v <= MOD) ? v : v % MOD;
		if (val < 0) val += MOD;
	}
	friend bool operator==(const mi& a, const mi& b) {
		return a.val == b.val; }
	friend bool operator!=(const mi& a, const mi& b) {
		return !(a == b); }
	friend bool operator<(const mi& a, const mi& b) {
		return a.val < b.val; }
	friend void re(mi& a) { ll x; re(x); a = mi(x); }
	friend void pr(const mi& a) { pr(a.val); }
	friend ostream& operator<<(ostream& os, const mi& a) {
		return os << a.val; }

	mi operator-() const { return mi(-val); }
	mi& operator+=(const mi& m) {
		if ((val += m.val) >= MOD) val -= MOD;
		return *this; }
	mi& operator-=(const mi& m) {
		if ((val -= m.val) < 0) val += MOD;
		return *this; }
	mi& operator++() { return *this += 1; }
	mi& operator--() { return *this -= 1; }
	friend mi operator+(mi a, const mi& b) { return a += b; }
	friend mi operator-(mi a, const mi& b) { return a -= b; }

	mi& operator*=(const mi& m) {
		val = (ll)val*m.val%MOD; return *this; }
	friend mi pow(mi a, ll p) {
		mi ans = 1; assert(p >= 0);
		for (; p; p /= 2, a *= a) if (p&1) ans *= a;
		return ans;
	}
	friend mi inv(const mi& a) {
		assert(!(a == 0)); return pow(a,MOD-2); }
	mi& operator/=(const mi& m) { return (*this) *= inv(m); }
	friend mi operator*(mi a, const mi& b) { return a *= b; }
	friend mi operator/(mi a, const mi& b) { return a /= b; }
};
typedef pair<mi,mi> pmi;
typedef vector<mi> vmi;
typedef vector<pmi> vpmi;

str hide = "abcdefbaawerewrra";
int n;

int comb(int x) { return x*(x+1)/2; }

multiset<str> m;
str res[101];

vs query(int l, int r) {
	if (l > r) return {};
	ps("?",l,r);
	vs v(comb(r-l+1)); re(v);
	// vs v; FOR(i,l,r+1) FOR(j,i,r+1) v.pb(hide.substr(i-1,j-i+1));
	trav(t,v) sort(all(t));
	return v;
}

int dif(str a, str b) {
	multiset<char> A(all(a));
	trav(t,b) A.erase(A.find(t));
	return *begin(A);
}

void fin(str s) {
	ps("!",s);
	exit(0);
}

int cur[105];

void FIN() {
	str res;
	FOR(i,1,n+1) res += char('a'+cur[i]);
	fin(res);
}

vector<pair<int,pi>> ADJ[105];

void ae(int l, int r, int x, int y) {
	// ps("ED",l,r);
	ADJ[l].pb({r,{x,y}}), ADJ[r].pb({l,{x,y}});
}

void gen(int l, int r) {
	if (l > r) return;
	l++, r++;
	// ps("CHECK",l,r);
	auto a = query(l,r);
	vi oc[105]; F0R(i,105) oc[i].rsz(26);
	trav(t,a) {
		//ps("WUT",t);
		trav(c,t) oc[sz(t)][c-'a'] ++;
	}
	int LEN = r-l+1; int hi = LEN/2;
	// FOR(i,1,LEN+1) ps(i,oc[i]);
	for (int len = 1; len <= hi; len++) {
		vi tmp(26);
		F0R(i,26) tmp[i] = (len+1)*oc[LEN][i]-oc[LEN-len][i];
		vi cool;
		F0R(i,26) F0R(j,tmp[i]) {
			cool.pb(i);
			FOR(z,len+1,hi+1) oc[LEN-z][i] -= len;
			oc[LEN][i] --;
		}
		//ps("??",len,cool);
		assert(sz(cool) == 2);
		ae(l+len-1,r-len+1,cool[0],cool[1]);
		//ps("HA",l,r,cool);
	}
	if (LEN&1) {
		int cnt = 0;
		F0R(i,sz(oc[LEN])) F0R(j,oc[LEN][i]) {
			ae(l+LEN/2,r-LEN/2,i,i);
			cnt ++;
		}
		assert(cnt == 1);
	}
	//exit(0);
}

void tri(int a, int b) {
	if (cur[a] != -1) return;
	cur[a] = b;
	trav(t,ADJ[a]) {
		if (t.s.f == b) tri(t.f,t.s.s);
		else tri(t.f,t.s.f);
	}
}

bool ok() {
	FOR(i,1,n+1) trav(t,ADJ[i]) {
		pi p = {cur[i],cur[t.f]};
		if (p == t.s || mp(p.s,p.f) == t.s) {

		} else return 0;
	}
	return 1;
}

int main() {
	// n = sz(hide);
	re(n);
	if (n == 1) {
		auto a = query(1,1);
		fin(a[0]);
	}
	int l,r;
	if (n%4 == 1) {
		l = n/2+2, r = n/2;
	} else {
		l = n/2-1, r = n/2;
	}
	// ps(l,r);
	gen(0,n-1), gen(0,l-1); gen(r,n-1);
	auto a = ADJ[1][0];
	FOR(i,1,n+1) cur[i] = -1;
	tri(1,a.s.f);
	// FOR(i,1,n+1) ps(i,cur[i]);
	if (ok()) FIN();
	FOR(i,1,n+1) cur[i] = -1;
	tri(1,a.s.s);
	if (ok()) FIN();
	exit(5);
	// you should actually read the stuff at the bottom
}

/* stuff you should look for
	* int overflow, array bounds
	* special cases (n=1?), slow multiset operations
	* do smth instead of nothing and stay organized
*/


#include<bits/stdc++.h>
using namespace std;
#define F first
#define S second
string Remove(string t,char a)
{
    int cnt[26]={0};
    for(int i=0;i<t.size();i++)
    {
        cnt[t[i]-'a']++;
    }
    cnt[a-'a']--;
    string ret;
    for(int i=0;i<26;i++)
    {
        for(int j=0;j<cnt[i];j++)
        {
            ret.push_back('a'+i);
            //cout<<"C"<<'a'+i<<'\n';
        }
    }
    //cout<<"RET"<<ret<<'\n';
    return ret;
}
string Add(string t,char a)
{
    int cnt[26]={0};
    for(int i=0;i<t.size();i++)
    {
        cnt[t[i]-'a']++;
    }
    cnt[a-'a']++;
    string ret;
    for(int i=0;i<26;i++)
    {
        for(int j=0;j<cnt[i];j++)
        {
            ret.push_back('a'+i);
        }
    }
    return ret;
}
char Cmp(string s,string s1)
{
    int cnt[26]={0};
    for(int i=0;i<s1.size();i++)
    {
        cnt[s1[i]-'a']++;
    }
    for(int i=0;i<s.size();i++)
    {
        cnt[s[i]-'a']--;
    }

    for(int i=0;i<26;i++)
    {
        //cout<<i<<' '<<cnt[i]<<'\n';
        if(cnt[i])
        {
            //cout<<"J"<<i<<'\n';
            return char('a'+i);
        }
    }
}
int main()
{
    int n;
    cin>>n;
    if(n==1)
    {
        cout<<"? 1 1"<<endl;
        string s;
        cin>>s;
        cout<<"! "<<s<<endl;
        return 0;
    }
    if(n==2)
    {
        cout<<"? 1 1"<<endl;
        string s1;
        cin>>s1;
        cout<<"? 2 2"<<endl;
        string s2;
        cin>>s2;
        cout<<"! "<<s1+s2<<endl;
        return 0;
    }
    map<string,int> s[105];
    map<string,int> tmp[105];
    string siz[105],siz2[105];
    char ans[105];
    cout<<"? 1 "<<(n+1)/2<<endl;
    for(int i=0;i<((n+1)/2+1)*((n+1)/2)/2;i++)
    {
        string t;
        cin>>t;
        sort(t.begin(),t.end());
        tmp[t.size()][t]++;
    }
    cout<<"? 2 "<<(n+1)/2<<endl;
    siz[0]="";
    for(int i=0;i<((n-1)/2+1)*((n-1)/2)/2;i++)
    {
        string t;
        cin>>t;
        sort(t.begin(),t.end());
        int sz=t.size();
        if(tmp[sz][t]>0) tmp[sz][t]--;
    }
    for(int i=1;i<=(n+1)/2;i++)
    {
        for(auto o:tmp[i])
        {
            if(o.S) siz[i]=o.F;
        }
    }
    string prev,now;
    for(int i=1;i<=(n+1)/2;i++)
    {
        ans[i]=Cmp(siz[i-1],siz[i]);
        //cout<<ans[i]<<'\n';
        prev=now;
    }
    cout<<"? 1 "<<n<<endl;
    string r;
    for(int i=1;i<=n*(n+1)/2;i++)
    {
        string t;
        cin>>t;
        sort(t.begin(),t.end());
        s[t.size()][t]++;
        if(t.size()>=n)
        {
            r=t;

        }
    }
    prev=r;
    now=r;
    string tmmp=r;
    for(int j=1;j<=(n+1)/2;j++)
    {
        tmmp=Remove(tmmp,ans[j]);
        //cout<<"T"<<ttmp<<'\n';
        s[tmmp.size()][tmmp]--;
    }
    for(int i=n-1;i>=(n+1)/2;i--)
    {
        for(auto o:s[i])
        {
            if(o.second)
            {
                now=o.first;
                //cout<<o.first<<' '<<o.second<<'\n';
            }
        }
        string ttmp=now;
        for(int j=1;j<=(n+1)/2;j++)
        {
            ttmp=Remove(ttmp,ans[j]);
            s[ttmp.size()][ttmp]--;
        }
        ans[i+1]=Cmp(now,prev);
        prev=now;
    }
    cout<<"! ";
    for(int i=1;i<=n;i++) cout<<ans[i];
    cout<<endl;
}


#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long ll1;
typedef double db;
const ll MAX=5e3+5;
ll MOD=1e9+7;
#define pb push_back
#define se second
#define fi first
#define sb __builtin_popcount
#define maxe max_element
#define mine min_element
#define debug(x) cout<<#x<<" :: "<<x<<endl;
#define debug2(x,y) cout<<#x<<" :: "<<x<<"\t"<<#y<<" :: "<<y<<endl;
#define debug3(x,y,z) cout<<#x<<" :: "<<x<<"\t"<<#y<<" :: "<<y<<"\t"<<#z<<" :: "<<z<<endl;
#define debug4(x,y,z,w) cout<<#x<<" :: "<<x<<"\t"<<#y<<" :: "<<y<<"\t"<<#z<<" :: "<<z<<"\t"<<#w<<" :: "<<w<<endl;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define fbo find_by_order
#define ook order_of_key
#define ub upper_bound
#define lb lower_bound
#define pq priority_queue
#define pll pair<ll,ll>
using namespace __gnu_pbds;
#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
ll add(ll a,ll b){return (a+b)%MOD;}
ll mul(ll a,ll b){return (a*b)%MOD;}
ll sub(ll a,ll b){return (a-b+MOD)%MOD;}
#define boost               ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define error 0.000000000000000001
#define dt pair<ll,pll>
map<string,ll>mp[101];
char fun(string s1,string s2)
{
	sort(s1.begin(),s1.end());
	sort(s2.begin(),s2.end());
	for(ll i=0;i<s1.length();i++)if(s1[i]!=s2[i])return s2[i];
	return s2.back();
}
int main()
{
	ll n;
	cin>>n;
	if(n==1){
		cout<<'?'<<' '<<1<<' '<<1<<'\n';
		string str;
		cin>>str;
		cout<<'!'<<' '<<str<<'\n';
		return 0;
	}
	cout<<'?'<<' '<<1<<' '<<n<<'\n';
	string str;
	for(ll i=0;i<(n*(n+1))/2;i++){
		cin>>str;
		sort(str.begin(),str.end());
		ll n=str.length();
		mp[n][str]++;
	}
	cout<<'?'<<' '<<2<<' '<<n<<'\n';
	for(ll i=0;i<(n*(n-1))/2;i++){
		cin>>str;
		sort(str.begin(),str.end());
		ll n=str.length();
		mp[n][str]--;
	}
	string s;
	for(ll i=1;i<=n;i++){
		for(pair<string,ll> u:mp[i]){
			if(u.se){
				char c=fun(s,u.fi);
				s.pb(c);
				break;
			}
		}
	}
	cout<<'!'<<' '<<s<<'\n';
	return 0;

}


#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long ll1;
typedef double db;
const ll MAX=5e3+5;
ll MOD=1e9+7;
#define pb push_back
#define se second
#define fi first
#define sb __builtin_popcount
#define maxe max_element
#define mine min_element
#define debug(x) cout<<#x<<" :: "<<x<<endl;
#define debug2(x,y) cout<<#x<<" :: "<<x<<"\t"<<#y<<" :: "<<y<<endl;
#define debug3(x,y,z) cout<<#x<<" :: "<<x<<"\t"<<#y<<" :: "<<y<<"\t"<<#z<<" :: "<<z<<endl;
#define debug4(x,y,z,w) cout<<#x<<" :: "<<x<<"\t"<<#y<<" :: "<<y<<"\t"<<#z<<" :: "<<z<<"\t"<<#w<<" :: "<<w<<endl;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define fbo find_by_order
#define ook order_of_key
#define ub upper_bound
#define lb lower_bound
#define pq priority_queue
#define pll pair<ll,ll>
using namespace __gnu_pbds;
#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
ll add(ll a,ll b){return (a+b)%MOD;}
ll mul(ll a,ll b){return (a*b)%MOD;}
ll sub(ll a,ll b){return (a-b+MOD)%MOD;}
#define boost               ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define error 0.000000000000000001
#define dt pair<ll,pll>
map<string,ll>mp[101];
vector<string>v[101];
ll cnt[101][26];
char fun(string s1,string s2)
{
	sort(s1.begin(),s1.end());
	sort(s2.begin(),s2.end());
	for(ll i=0;i<s1.length();i++)if(s1[i]!=s2[i])return s2[i];
	return s2.back();
}
int main()
{
	ll n1;
	cin>>n1;
	ll n=(n1+1)/2;
	if(n1==1){
		cout<<'?'<<' '<<1<<' '<<1<<'\n';
		string str;
		cin>>str;
		cout<<'!'<<' '<<str<<'\n';
		return 0;
	}
	if(n1==2){
		string s;
		cout<<'?'<<' '<<1<<' '<<1<<'\n';
		char str;
		cin>>str;
		s.pb(str);
		cout<<'?'<<' '<<2<<' '<<2<<'\n';
		cin>>str;
		s.pb(str);
		cout<<'!'<<' '<<s<<'\n';
		return 0;
	}
	cout<<'?'<<' '<<1<<' '<<n<<'\n';
	string str;
	for(ll i=0;i<(n*(n+1))/2;i++){
		cin>>str;
		sort(str.begin(),str.end());
		ll n=str.length();
		mp[n][str]++;
	}
	cout<<'?'<<' '<<2<<' '<<n<<'\n';
	for(ll i=0;i<(n*(n-1))/2;i++){
		cin>>str;
		sort(str.begin(),str.end());
		ll n=str.length();
		mp[n][str]--;
	}
	string s;
	for(ll i=1;i<=n;i++){
		for(pair<string,ll> u:mp[i]){
			if(u.se){
				char c=fun(s,u.fi);
				s.pb(c);
				break;
			}
		}
	}
	cout<<'?'<<' '<<1<<' '<<n1<<'\n';
	for(ll i=0;i<(n1*(n1+1))/2;i++){
		cin>>str;
		v[str.length()].pb(str);
	}
	for(ll i=1;i<=n1;i++){
		for(string u:v[i]){
			for(char c:u){
				cnt[i][c-'a']++;
			}
		}
	}
	map<char,ll>cnt1;
	ll curr=n1/2;
	curr--;// to make 0-indexing
	if(n1&1)cnt1[s[curr+1]]++;
	for(ll i=(n1+1)/2,l=n1/2;i<n1;i++,l--){
		cnt1[s[curr--]]++;
		for(ll j=0;j<26;j++){
			ll x=cnt[l][j]-cnt[l-1][j];
			//debug4(x,l,cnt[l][j],cnt[l-1][j]);
			if(x!=cnt1[j+'a']){
				s.pb(j+'a');
				break;
			}
		}
		cnt1[s[i]]++;
	}
	cout<<'!'<<' '<<s<<'\n';
}


#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long ll1;
typedef double db;
const ll MAX=5e3+5;
ll MOD=1e9+7;
#define pb push_back
#define se second
#define fi first
#define sb __builtin_popcount
#define maxe max_element
#define mine min_element
#define debug(x) cout<<#x<<" :: "<<x<<endl;
#define debug2(x,y) cout<<#x<<" :: "<<x<<"\t"<<#y<<" :: "<<y<<endl;
#define debug3(x,y,z) cout<<#x<<" :: "<<x<<"\t"<<#y<<" :: "<<y<<"\t"<<#z<<" :: "<<z<<endl;
#define debug4(x,y,z,w) cout<<#x<<" :: "<<x<<"\t"<<#y<<" :: "<<y<<"\t"<<#z<<" :: "<<z<<"\t"<<#w<<" :: "<<w<<endl;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define fbo find_by_order
#define ook order_of_key
#define ub upper_bound
#define lb lower_bound
#define pq priority_queue
#define pll pair<ll,ll>
using namespace __gnu_pbds;
#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
ll add(ll a,ll b){return (a+b)%MOD;}
ll mul(ll a,ll b){return (a*b)%MOD;}
ll sub(ll a,ll b){return (a-b+MOD)%MOD;}
#define boost               ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define error 0.000000000000000001
#define dt pair<ll,pll>
map<string,ll>mp[101];
vector<string>v[101];
ll cnt[101][26];
char fun(string s1,string s2)
{
	sort(s1.begin(),s1.end());
	sort(s2.begin(),s2.end());
	for(ll i=0;i<s1.length();i++)if(s1[i]!=s2[i])return s2[i];
	return s2.back();
}
int main()
{
	ll n1;
	cin>>n1;
	ll n=(n1+1)/2;
	if(n1==1){
		cout<<'?'<<' '<<1<<' '<<1<<'\n';
		string str;
		cin>>str;
		cout<<'!'<<' '<<str<<'\n';
		return 0;
	}
	cout<<'?'<<' '<<1<<' '<<n<<'\n';
	string str;
	for(ll i=0;i<(n*(n+1))/2;i++){
		cin>>str;
		sort(str.begin(),str.end());
		ll n=str.length();
		mp[n][str]++;
	}
	cout<<'?'<<' '<<2<<' '<<n<<'\n';
	for(ll i=0;i<(n*(n-1))/2;i++){
		cin>>str;
		sort(str.begin(),str.end());
		ll n=str.length();
		mp[n][str]--;
	}
	string s;
	for(ll i=1;i<=n;i++){
		for(pair<string,ll> u:mp[i]){
			if(u.se){
				char c=fun(s,u.fi);
				s.pb(c);
				break;
			}
		}
	}
	cout<<'?'<<' '<<1<<' '<<n1<<'\n';
	for(ll i=0;i<(n1*(n1+1))/2;i++){
		cin>>str;
		v[str.length()].pb(str);
	}
	for(ll i=1;i<=n1;i++){
		for(string u:v[i]){
			for(char c:u){
				cnt[i][c-'a']++;
			}
		}
	}
	map<char,ll>cnt1;
	ll curr=n1/2;
	curr--;// to make 0-indexing
	if(n&1)cnt1[s[curr+1]]++;
	for(ll i=(n1+1)/2,l=n1/2;i<n1;i++,l--){
		cnt1[s[curr--]]++;
		for(ll j=0;j<26;j++){
			ll x=cnt[l][j]-cnt[l-1][j];
			//debug4(x,l,cnt[l][j],cnt[l-1][j]);
			if(x!=cnt1[j+'a']){
				s.pb(j+'a');
				break;
			}
		}
		cnt1[s[i]]++;
	}
	cout<<'!'<<' '<<s<<'\n';
}


#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long ll1;
typedef double db;
const ll MAX=5e3+5;
ll MOD=1e9+7;
#define pb push_back
#define se second
#define fi first
#define sb __builtin_popcount
#define maxe max_element
#define mine min_element
#define debug(x) cout<<#x<<" :: "<<x<<endl;
#define debug2(x,y) cout<<#x<<" :: "<<x<<"\t"<<#y<<" :: "<<y<<endl;
#define debug3(x,y,z) cout<<#x<<" :: "<<x<<"\t"<<#y<<" :: "<<y<<"\t"<<#z<<" :: "<<z<<endl;
#define debug4(x,y,z,w) cout<<#x<<" :: "<<x<<"\t"<<#y<<" :: "<<y<<"\t"<<#z<<" :: "<<z<<"\t"<<#w<<" :: "<<w<<endl;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define fbo find_by_order
#define ook order_of_key
#define ub upper_bound
#define lb lower_bound
#define pq priority_queue
#define pll pair<ll,ll>
using namespace __gnu_pbds;
#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
ll add(ll a,ll b){return (a+b)%MOD;}
ll mul(ll a,ll b){return (a*b)%MOD;}
ll sub(ll a,ll b){return (a-b+MOD)%MOD;}
#define boost               ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define error 0.000000000000000001
#define dt pair<ll,pll>
map<string,ll>mp[101];
vector<string>v[101];
ll cnt[101][26];
char fun(string s1,string s2)
{
	sort(s1.begin(),s1.end());
	sort(s2.begin(),s2.end());
	for(ll i=0;i<s1.length();i++)if(s1[i]!=s2[i])return s2[i];
	return s2.back();
}
int main()
{
	ll n1;
	cin>>n1;
	ll n=(n1+1)/2;
	if(n1==1){
		cout<<'?'<<' '<<1<<' '<<1<<'\n';
		string str;
		cin>>str;
		cout<<'!'<<' '<<str<<'\n';
		return 0;
	}
	if(n1==2){
		string s;
		cout<<'?'<<' '<<1<<' '<<1<<'\n';
		char str;
		cin>>str;
		s.pb(str);
		cout<<'?'<<' '<<2<<' '<<2<<'\n';
		cin>>str;
		s.pb(str);
		cout<<'!'<<' '<<s<<'\n';
		return 0;
	}
	cout<<'?'<<' '<<1<<' '<<n<<'\n';
	string str;
	for(ll i=0;i<(n*(n+1))/2;i++){
		cin>>str;
		sort(str.begin(),str.end());
		ll n=str.length();
		mp[n][str]++;
	}
	cout<<'?'<<' '<<2<<' '<<n<<'\n';
	for(ll i=0;i<(n*(n-1))/2;i++){
		cin>>str;
		sort(str.begin(),str.end());
		ll n=str.length();
		mp[n][str]--;
	}
	string s;
	for(ll i=1;i<=n;i++){
		for(pair<string,ll> u:mp[i]){
			if(u.se){
				char c=fun(s,u.fi);
				s.pb(c);
				break;
			}
		}
	}
	cout<<'?'<<' '<<1<<' '<<n1<<'\n';
	for(ll i=0;i<(n1*(n1+1))/2;i++){
		cin>>str;
		v[str.length()].pb(str);
	}
	for(ll i=1;i<=n1;i++){
		for(string u:v[i]){
			for(char c:u){
				cnt[i][c-'a']++;
			}
		}
	}
	map<char,ll>cnt1;
	ll curr=n1/2;
	curr--;// to make 0-indexing
	if(n&1)cnt1[s[curr+1]]++;
	for(ll i=(n1+1)/2,l=n1/2;i<n1;i++,l--){
		cnt1[s[curr--]]++;
		for(ll j=0;j<26;j++){
			ll x=cnt[l][j]-cnt[l-1][j];
			//debug4(x,l,cnt[l][j],cnt[l-1][j]);
			if(x!=cnt1[j+'a']){
				s.pb(j+'a');
				break;
			}
		}
		cnt1[s[i]]++;
	}
	cout<<'!'<<' '<<s<<'\n';
}


#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof (x))
#define For(i,a,b) for (int i=(a);i<=(b);i++)
#define Fod(i,b,a) for (int i=(b);i>=(a);i--)
#define fi first
#define se second
#define kill _z_kill
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define outval(x) cerr<<#x" = "<<x<<endl
#define outv(x) cerr<<#x" = "<<x<<"  "
#define outtag(x) cerr<<"--------------"#x"---------------"<<endl
#define outarr(a,L,R) cerr<<#a"["<<L<<".."<<R<<"] = ";\
	For(_x,L,R) cerr<<a[_x]<<" ";cerr<<endl;
#define User_Time ((double)clock()/CLOCKS_PER_SEC)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef unsigned uint;
typedef long double LD;
typedef vector <int> vi;
typedef pair <int,int> pii;
LL read(){
	LL x=0,f=0;
	char ch=getchar();
	while (!isdigit(ch))
		f=ch=='-',ch=getchar();
	while (isdigit(ch))
		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return f?-x:x;
}
template <class T> void ckmax(T &x,T y){
	if (x<y)
		x=y;
}
template <class T> void ckmin(T &x,T y){
	if (x>y)
		x=y;
}
//int Pow(int x,int y){
//	int ans=1;
//	for (;y;y>>=1,x=(LL)x*x%mod)
//		if (y&1)
//			ans=(LL)ans*x%mod;
//	return ans;
//}
//void Add(int &x,int y){
//	if ((x+=y)>=mod)
//		x-=mod;
//}
//void Del(int &x,int y){
//	if ((x-=y)<0)
//		x+=mod;
//}
//int Add(int x){
//	return x>=mod?x-mod:x;
//}
//int Del(int x){
//	return x<0?x+mod:x;
//}
const int N=105;
int n;
struct cmp{
	bool operator () (string a,string b){
		if (a.size()!=b.size())
			return a.size()<b.size();
		return a<b;
	}
};
typedef multiset <string,cmp> ms;
ms query(int L,int R){
	ms res;
	if (L>R)
		return res;
	printf("? %d %d\n",L,R);
	fflush(stdout);
	string s;
	For(_,1,(R-L+2)*(R-L+1)/2){
		cin>>s;
		sort(s.begin(),s.end());
		res.insert(s);
	}
	return res;
}
void answer(char *s){
	For(i,1,n)
		putchar(s[i]);
	puts("");
	fflush(stdout);
	exit(0);
}
char s[N];
int main(){
	n=read();
	if (n==1)
		s[1]=(*query(1,1).begin())[0],answer(s);
	int mid=n/2;
	ms s0=query(1,mid-1);
	ms s1=query(1,mid);
	ms s2=query(1,n);
	for (auto i : s0)
		s1.erase(s1.find(i));
	{
		int p=mid;
		string las="";
		for (auto i : s1){
			vi cnt(26,0);
			for (auto c : i)
				cnt[c-'a']++;
			for (auto c : las)
				cnt[c-'a']--;
			For(i,0,25)
				if (cnt[i]){
					s[p--]='a'+i;
					break;
				}
			las=i;
		}
	}
	string ss=*prev(s2.end()),sl=*prev(s1.end());
	outval(sl);
	vi cs(26,0);
	for (auto c : ss)
		cs[c-'a']++;
	for (auto c : sl)
		cs[c-'a']--;
	outarr(cs,0,3);
	s2.insert("");
	Fod(i,n,mid+1){
		string now="";
		For(i,0,25)
			For(j,1,cs[i])
				now+='a'+i;
		if (i==mid+1){
//			outval(now);
			assert(now.size()==1);
			s[i]=now[0];
			answer(s);
		}
		Fod(j,mid,1){
			sort(now.begin(),now.end());
			s2.erase(s2.find(now));
			now+=s[j];
		}
		sort(now.begin(),now.end());
		s2.erase(s2.find(now));
		string snxt=*prev(s2.end());
		vi cnt(26,0);
		for (auto c : snxt)
			cnt[c-'a']++;
		for (auto c : sl)
			cnt[c-'a']--;
		For(c,0,25)
			if (cnt[c]!=cs[c]){
				s[i]='a'+c;
				break;
			}
		cs=cnt;
	}
	return 0;
}


#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof (x))
#define For(i,a,b) for (int i=(a);i<=(b);i++)
#define Fod(i,b,a) for (int i=(b);i>=(a);i--)
#define fi first
#define se second
#define kill _z_kill
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define outval(x) cerr<<#x" = "<<x<<endl
#define outv(x) cerr<<#x" = "<<x<<"  "
#define outtag(x) cerr<<"--------------"#x"---------------"<<endl
#define outarr(a,L,R) cerr<<#a"["<<L<<".."<<R<<"] = ";\
	For(_x,L,R) cerr<<a[_x]<<" ";cerr<<endl;
#define User_Time ((double)clock()/CLOCKS_PER_SEC)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef unsigned uint;
typedef long double LD;
typedef vector <int> vi;
typedef pair <int,int> pii;
LL read(){
	LL x=0,f=0;
	char ch=getchar();
	while (!isdigit(ch))
		f=ch=='-',ch=getchar();
	while (isdigit(ch))
		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return f?-x:x;
}
template <class T> void ckmax(T &x,T y){
	if (x<y)
		x=y;
}
template <class T> void ckmin(T &x,T y){
	if (x>y)
		x=y;
}
//int Pow(int x,int y){
//	int ans=1;
//	for (;y;y>>=1,x=(LL)x*x%mod)
//		if (y&1)
//			ans=(LL)ans*x%mod;
//	return ans;
//}
//void Add(int &x,int y){
//	if ((x+=y)>=mod)
//		x-=mod;
//}
//void Del(int &x,int y){
//	if ((x-=y)<0)
//		x+=mod;
//}
//int Add(int x){
//	return x>=mod?x-mod:x;
//}
//int Del(int x){
//	return x<0?x+mod:x;
//}
const int N=105;
int n;
struct cmp{
	bool operator () (string a,string b){
		if (a.size()!=b.size())
			return a.size()<b.size();
		return a<b;
	}
};
typedef multiset <string,cmp> ms;
ms query(int L,int R){
	ms res;
	if (L>R)
		return res;
	printf("? %d %d\n",L,R);
	fflush(stdout);
	string s;
	For(_,1,(R-L+2)*(R-L+1)/2){
		cin>>s;
		sort(s.begin(),s.end());
		res.insert(s);
	}
	return res;
}
void answer(char *s){
	printf("! ");
	For(i,1,n)
		putchar(s[i]);
	puts("");
	fflush(stdout);
	exit(0);
}
char s[N];
int main(){
	n=read();
	if (n==1)
		s[1]=(*query(1,1).begin())[0],answer(s);
	int mid=n/2;
	ms s0=query(1,mid-1);
	ms s1=query(1,mid);
	ms s2=query(1,n);
	for (auto i : s0)
		s1.erase(s1.find(i));
	{
		int p=mid;
		string las="";
		for (auto i : s1){
			vi cnt(26,0);
			for (auto c : i)
				cnt[c-'a']++;
			for (auto c : las)
				cnt[c-'a']--;
			For(i,0,25)
				if (cnt[i]){
					s[p--]='a'+i;
					break;
				}
			las=i;
		}
	}
	string ss=*prev(s2.end()),sl=*prev(s1.end());
	outval(sl);
	vi cs(26,0);
	for (auto c : ss)
		cs[c-'a']++;
	for (auto c : sl)
		cs[c-'a']--;
	outarr(cs,0,3);
	s2.insert("");
	Fod(i,n,mid+1){
		string now="";
		For(i,0,25)
			For(j,1,cs[i])
				now+='a'+i;
		if (i==mid+1){
//			outval(now);
			assert(now.size()==1);
			s[i]=now[0];
			answer(s);
		}
		Fod(j,mid,1){
			sort(now.begin(),now.end());
			s2.erase(s2.find(now));
			now+=s[j];
		}
		sort(now.begin(),now.end());
		s2.erase(s2.find(now));
		string snxt=*prev(s2.end());
		vi cnt(26,0);
		for (auto c : snxt)
			cnt[c-'a']++;
		for (auto c : sl)
			cnt[c-'a']--;
		For(c,0,25)
			if (cnt[c]!=cs[c]){
				s[i]='a'+c;
				break;
			}
		cs=cnt;
	}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#ifndef ONLINE_JUDGE
#define dbg(x...) do{cout << "\033[32;1m" << #x << "->" ; err(x);} while(0)
void err(){cout << "\033[39;0m" << endl;}
template<template<typename...> class T,typename t,typename... A>
void err(T<t> a,A... x){for (auto v:a) cout << v << ' '; err(x...);}
template<typename T,typename... A>
void err(T a,A... x){cout << a << ' '; err(x...);}
#else
#define dbg(...)
#endif
typedef long long ll;
typedef pair<int,int> pi;
typedef vector<int> vi;
template<class T> using vc=vector<T>;
template<class T> using vvc=vc<vc<T>>;
template<class T> void mkuni(vector<T>&v)
{
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
}
template<class T>
void print(T x,int suc=1)
{
    cout<<x;
    if(suc==1) cout<<'\n';
    else cout<<' ';
}
template<class T>
void print(const vector<T>&v,int suc=1)
{
    for(int i=0;i<v.size();i++)
        print(v[i],i==(int)(v.size())-1?suc:2);
}
const int INF=0x3f3f3f3f;
vc<string> ask(int l,int r)
{
	cout<<"? "<<l<<" "<<r<<endl;
	int len=r-l+1;
	vc<string> ret;
	for(int i=0;i<len*(len+1)/2;i++)
	{
		string cur;
		cin>>cur;
		sort(cur.begin(),cur.end());
		ret.push_back(cur);
	}
	return ret;
}
map<string,int> cnt;
void answer(string s)
{
	cout<<"! "<<s<<endl;
}
int main()
{
	int n;
	cin>>n;
	if(n==1)
		answer(ask(1,1)[0]);
	else{
		auto A=ask(1,(n+1)/2);
		auto B=ask(1,n/2-(n%2==0));
		for(auto u:A)
			cnt[u]++;
		for(auto u:B)
			cnt[u]--;
		vc<string> all;
		string ans;
		for(auto u:cnt)
		{
			if(u.second)
				all.push_back(u.first);
		}
		sort(all.begin(),all.end(),[&](string i,string j){return i.length()<j.length();});
		int cc[30];
		memset(cc,0,sizeof(cc));
		for(auto u:all)
		{
			int cur[30];
			memset(cur,0,sizeof(cur));
			for(auto v:u)
				cur[v-'a']++;
			for(int i=0;i<30;i++)
			{
				if(cur[i]>cc[i])
				{
					cc[i]++;
					ans+=(i+'a');
					break;
				}
			}
		}
		A=ask(1,n);
		int cl[105][30];
		memset(cl,0,sizeof(cl));
		for(auto u:A)
		{
			for(auto v:u)
				cl[u.length()][v-'a']++;
		}
		for(int i=(n+1)/2+1;i<=n;i++)
		{
			int len=n-i;
	//		dbg(i,len);
			memset(cc,0,sizeof(cc));
			for(int j=len;j<i;j++)
				cc[ans[j]-'a']++;
			for(int j=0;j<30;j++)
			{
				int xx=cl[len+1][j]-cl[len][j];
				if(xx!=cc[j])
				{
					ans+=(j+'a');
					break;
				}
			}
		}
		answer(ans);
	}

}


#include<bits/stdc++.h>
using namespace std;
#ifndef ONLINE_JUDGE
#define dbg(x...) do{cout << "\033[32;1m" << #x << "->" ; err(x);} while(0)
void err(){cout << "\033[39;0m" << endl;}
template<template<typename...> class T,typename t,typename... A>
void err(T<t> a,A... x){for (auto v:a) cout << v << ' '; err(x...);}
template<typename T,typename... A>
void err(T a,A... x){cout << a << ' '; err(x...);}
#else
#define dbg(...)
#endif
typedef long long ll;
typedef pair<int,int> pi;
typedef vector<int> vi;
template<class T> using vc=vector<T>;
template<class T> using vvc=vc<vc<T>>;
template<class T> void mkuni(vector<T>&v)
{
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
}
template<class T>
void print(T x,int suc=1)
{
    cout<<x;
    if(suc==1) cout<<'\n';
    else cout<<' ';
}
template<class T>
void print(const vector<T>&v,int suc=1)
{
    for(int i=0;i<v.size();i++)
        print(v[i],i==(int)(v.size())-1?suc:2);
}
const int INF=0x3f3f3f3f;
vc<string> ask(int l,int r)
{
	cout<<"? "<<l<<" "<<r<<endl;
	int len=r-l+1;
	vc<string> ret;
	for(int i=0;i<len*(len+1)/2;i++)
	{
		string cur;
		cin>>cur;
		sort(cur.begin(),cur.end());
		ret.push_back(cur);
	}
	return ret;
}
map<string,int> cnt;
void answer(string s)
{
	cout<<"! "<<s<<endl;
}
int main()
{
	int n;
	cin>>n;
	if(n==1)
		answer(ask(1,1)[0]);
	else if(n==2)
	{
		string aa;
		aa+=ask(1,1)[0];
		aa+=ask(2,2)[0];
		answer(aa);
	}
	else{
		auto A=ask(1,(n+1)/2);
		auto B=ask(2,(n+1)/2);
		for(auto u:A)
			cnt[u]++;
		for(auto u:B)
			cnt[u]--;
		vc<string> all;
		string ans;
		for(auto u:cnt)
		{
			if(u.second)
				all.push_back(u.first);
		}
		sort(all.begin(),all.end(),[&](string i,string j){return i.length()<j.length();});
		int cc[30];
		memset(cc,0,sizeof(cc));
		for(auto u:all)
		{
			int cur[30];
			memset(cur,0,sizeof(cur));
			for(auto v:u)
				cur[v-'a']++;
			for(int i=0;i<30;i++)
			{
				if(cur[i]>cc[i])
				{
					cc[i]++;
					ans+=(i+'a');
					break;
				}
			}
		}
		dbg(ans);
		A=ask(1,n);
		int cl[105][30];
		memset(cl,0,sizeof(cl));
		for(auto u:A)
		{
			for(auto v:u)
				cl[u.length()][v-'a']++;
		}
		for(int i=(n+1)/2+1;i<=n;i++)
		{
			int len=n-i;
	//		dbg(i,len);
			memset(cc,0,sizeof(cc));
			for(int j=len;j<i;j++)
				cc[ans[j]-'a']++;
			for(int j=0;j<30;j++)
			{
				int xx=cl[len+1][j]-cl[len][j];
				if(xx!=cc[j])
				{
					ans+=(j+'a');
					break;
				}
			}
		}
		answer(ans);
	}

}


#include<bits/stdc++.h>
using namespace std;
#ifndef ONLINE_JUDGE
#define dbg(x...) do{cout << "\033[32;1m" << #x << "->" ; err(x);} while(0)
void err(){cout << "\033[39;0m" << endl;}
template<template<typename...> class T,typename t,typename... A>
void err(T<t> a,A... x){for (auto v:a) cout << v << ' '; err(x...);}
template<typename T,typename... A>
void err(T a,A... x){cout << a << ' '; err(x...);}
#else
#define dbg(...)
#endif
typedef long long ll;
typedef pair<int,int> pi;
typedef vector<int> vi;
template<class T> using vc=vector<T>;
template<class T> using vvc=vc<vc<T>>;
template<class T> void mkuni(vector<T>&v)
{
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
}
template<class T>
void print(T x,int suc=1)
{
    cout<<x;
    if(suc==1) cout<<'\n';
    else cout<<' ';
}
template<class T>
void print(const vector<T>&v,int suc=1)
{
    for(int i=0;i<v.size();i++)
        print(v[i],i==(int)(v.size())-1?suc:2);
}
const int INF=0x3f3f3f3f;
vc<string> ask(int l,int r)
{
	cout<<"? "<<l<<" "<<r<<endl;
	int len=r-l+1;
	vc<string> ret;
	for(int i=0;i<len*(len+1)/2;i++)
	{
		string cur;
		cin>>cur;
		sort(cur.begin(),cur.end());
		ret.push_back(cur);
	}
	return ret;
}
map<string,int> cnt;
void answer(string s)
{
	cout<<"! "<<s<<endl;
}
int main()
{
	int n;
	cin>>n;
	if(n==1)
		answer(ask(1,1)[0]);
	else{
		auto A=ask(1,(n+1)/2);
		auto B=ask(2,(n+1)/2);
		for(auto u:A)
			cnt[u]++;
		for(auto u:B)
			cnt[u]--;
		vc<string> all;
		string ans;
		for(auto u:cnt)
		{
			if(u.second)
				all.push_back(u.first);
		}
		sort(all.begin(),all.end(),[&](string i,string j){return i.length()<j.length();});
		int cc[30];
		memset(cc,0,sizeof(cc));
		for(auto u:all)
		{
			int cur[30];
			memset(cur,0,sizeof(cur));
			for(auto v:u)
				cur[v-'a']++;
			for(int i=0;i<30;i++)
			{
				if(cur[i]>cc[i])
				{
					cc[i]++;
					ans+=(i+'a');
					break;
				}
			}
		}
		dbg(ans);
		A=ask(1,n);
		int cl[105][30];
		memset(cl,0,sizeof(cl));
		for(auto u:A)
		{
			for(auto v:u)
				cl[u.length()][v-'a']++;
		}
		for(int i=(n+1)/2+1;i<=n;i++)
		{
			int len=n-i;
	//		dbg(i,len);
			memset(cc,0,sizeof(cc));
			for(int j=len;j<i;j++)
				cc[ans[j]-'a']++;
			for(int j=0;j<30;j++)
			{
				int xx=cl[len+1][j]-cl[len][j];
				if(xx!=cc[j])
				{
					ans+=(j+'a');
					break;
				}
			}
		}
		answer(ans);
	}

}


#include <bits/stdc++.h>

template <class T>
inline void read(T &x)
{
	static char ch;
	static bool opt;
	while (!isdigit(ch = getchar()) && ch != '-');
	x = (opt = ch == '-') ? 0 : ch - '0';
	while (isdigit(ch = getchar()))
		x = x * 10 + ch - '0';
	if (opt)
		x = ~x + 1;
}

template <class T>
inline void putint(T x)
{
	static char buf[45], *tail = buf;
	if (!x)
		putchar('0');
	else
	{
		if (x < 0)
			putchar('-'), x = ~x + 1;
		for (; x; x /= 10) *++tail = x % 10 + '0';
		for (; tail != buf; --tail) putchar(*tail);
	}
}

template <class T>
inline bool tense(T &x, const T &y)
{
	return y < x ? x = y, true : false;
}

template <class T>
inline bool relax(T &x, const T &y)
{
	return x < y ? x = y, true : false;
}

using std::min;
using std::max;
using std::pair;
using std::cin;
using std::cout;
using std::vector;
using std::multiset;
using std::string;
typedef long long s64;
typedef long double ld;
typedef std::pair<int, int> pii;
#define mp(x, y) std::make_pair(x, y)

const int MaxN = 110;

int n, m;
char ans[MaxN];
string s, t[MaxN];

struct number
{
	int a[26];
	inline number operator + (number rhs) const
	{
		number res;
		for (int i = 0; i < 26; ++i)
			res.a[i] = a[i] + rhs.a[i];
		return res;
	}
	inline number operator - (number rhs) const
	{
		number res;
		for (int i = 0; i < 26; ++i)
			res.a[i] = a[i] - rhs.a[i];
		return res;
	}
	inline bool operator != (number rhs) const
	{
		for (int i = 0; i < 26; ++i)
			if (a[i] != rhs.a[i])
				return true;
		return false;
	}
	inline bool operator < (number rhs) const
	{
		for (int i = 0; i < 26; ++i)
			if (a[i] != rhs.a[i])
				return a[i] < rhs.a[i];
		return false;
	}
	inline bool only1() const
	{
		bool has = false;
		for (int i = 0; i < 26; ++i)
			if (a[i] == 1 && !has)
				has = true;
			else if (a[i])
				return false;
		return has;
	}
	inline char get1() const
	{
		for (int i = 0; i < 26; ++i)
			if (a[i])
				return i + 'a';
		return 0;
	}

	inline void print()
	{
		for (int i = 0; i < 26; ++i)
			if (a[i] >= 0)
			{

				for (int j = 0; j < a[i]; ++j)
					printf("%c", i + 'a');
			}
			else
				printf("%c", i + 'a'), printf("nan");
	}
}all[MaxN], pans[MaxN];

multiset<number> S;

inline void query(int l, int r)
{
	printf("? %d %d\n", l, r);
	fflush(stdout);
}

inline int calc(int n)
{
	return (n * (n - 1) >> 1) + n;
}

number convert(char c)
{
	number res;
	memset(res.a, 0, sizeof(res.a));
	++res.a[c - 'a'];
	return res;
}

number convert(string s)
{
	number res;
	memset(res.a, 0, sizeof(res.a));
	int len = s.length();
	for (int i = 0; i < len; ++i)
		++res.a[s[i] - 'a'];
	return res;
}

inline void solve(int n)
{
	query(1, n);
	for (int i = 1; i <= calc(n); ++i)
	{
		std::cin >> s;
		S.insert(convert(s));
	}
	if (n == 1)
	{
		ans[1] = (S.begin())->get1();
		return;
	}

	query(2, n);
	for (int i = 1; i <= calc(n - 1); ++i)
	{
		std::cin >> s;
		S.erase(S.find(convert(s)));
	}
	for (int i = 1; i <= n; ++i)
	{
		number tmp;
		for (auto t : S)
			if (t.only1())
			{
				tmp = t;
				ans[i] = t.get1();
				S.erase(S.find(t));
				break;
			}

		multiset<number> T;
		T.clear();
		for (auto w : S)
			T.insert(w - tmp);
		S = T;
	}
}

int main()
{
#ifdef orzczk
	freopen("tmp.in", "r", stdin);
#endif

	read(n);
	if (n == 1)
	{
		query(1, n);
		std::cin >> s;
		std::cout << "! " << s << '\n';
		return 0;
	}

	m = n >> 1;
	query(1, n);
	for (int i = 1, lim = calc(n); i <= lim; ++i)
	{
		std::cin >> s;
		int len = s.length();
		all[len] = all[len] + convert(s);
	}
	for (int i = 1; i <= m; ++i)
	{
		pans[i] = all[i + 1];
		for (int j = 0; j < i; ++j)
			for (int k = 1; k <= i - j + 1; ++k)
				pans[i] = pans[i] + pans[j];
		for (int j = 1; j <= i + 1; ++j)
			pans[i] = pans[i] - all[1];
		for (int j = 0; j < 26; ++j)
			pans[i].a[j] = -pans[i].a[j];

	//	printf("%d\n", i);
	//	pans[i].print(); puts("");
	}
	if (n & 1)
	{
		number tmp = all[1];
		for (int i = 1; i <= m; ++i)
			tmp = tmp - pans[i];
		ans[m + 1] = tmp.get1();
	}

	solve(m);
	for (int i = 1; i <= m; ++i)
		ans[n - i + 1] = (pans[i] - convert(ans[i])).get1();

	printf("! ");
	for (int i = 1; i <= n; ++i)
		putchar(ans[i]);

	return 0;
}


#include <bits/stdc++.h>

using namespace std;

string ans, res;
multiset <string> ST[110];
int n;

void ask(int L, int R, int ok){
	cout << '?' << ' ' << L << ' ' << R << endl;
	int N = (R - L + 1) * (R - L + 2) / 2;
	for(int i=1; i<=N; i++){
		string t;
		cin >> t;
		int sz = t.size();
		sort(t.begin(), t.end());
		if(ok) ST[sz].insert(t);
		else ST[sz].erase(ST[sz].find(t));
		if(n == 1){
			cout << '!' << ' ' << t[0] << endl;
			exit(0);
		}
	}
}

int cnt[26];

int main() {

	ios_base :: sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n;
	int p = (n + 1) / 2, q = n - p;
	ask(1, p, 1);
	if(p != 1) ask(2, p, 0);
	for(int i=1; i<=p; i++){
		string t = *ST[i].begin();
		for(int j=0; j<t.size(); j++){
			cnt[t[j] - 'a']++;
		}
		for(int j=0; j<26; j++){
			if(cnt[j]){
				ans += 'a' + j;
				break;
			}
		}
		memset(cnt, 0, sizeof cnt);
		for(int j=0; j<t.size(); j++){
			cnt[t[j] - 'a']--;
		}
		ST[i].clear();
	}
	ask(1, n, 1);
	string tot = *ST[n].begin();

	for(int i=1; i<=q; i++){
		int x = n - i;
		for(int L=1; L<=n-x; L++){
			int R = L + x - 1;
			memset(cnt, 0, sizeof cnt);
			for(int j=0; j<tot.size(); j++){
				cnt[tot[j] - 'a']++;
			}
			for(int j=0; j<L; j++){
				cnt[ans[j] - 'a']--;
			}
			for(int j=0; j<n-R-1; j++){
				cnt[res[j] - 'a']--;
			}
			string t;
			for(int j=0; j<26; j++){
				while(cnt[j]){
					cnt[j]--;
					t += 'a' + j;
				}
			}
			ST[x].erase(ST[x].find(t));
		}
		string t = *ST[x].begin();
		memset(cnt, 0, sizeof cnt);
		for(int j=0; j<tot.size(); j++){
			cnt[tot[j] - 'a']++;
		}
		for(int j=0; j<t.size(); j++){
			cnt[t[j] - 'a']--;
		}
		for(int j=0; j<res.size(); j++){
			cnt[res[j] - 'a']--;
		}
		for(int j=0; j<26; j++){
			if(cnt[j]){
				res += 'a' + j;
				break;
			}
		}
	}
	for(int i=res.size()-1; i>=0; i--){
		ans += res[i];
	}
	cout << '!' << ' ' << ans << endl;
}


#include<bits/stdc++.h>
using namespace std;

vector<string> besar,kecil,v[105],sisa;
int brp[26],prv[26],now[26],last[26];

bool cmp(string a,string t){
	return a.length()<t.length();
}

int main(){
	int n;
	string s;
	cin >> n;
	if(n<=3){
		string ans="";
		for(int i=1;i<=n;i++){
			cout << "? " << i << " " << i << endl;
			cin >> s;
			ans+=s;
		}
		cout << "! " << ans << endl;
		return 0;
	}
	cout << "? 1 " << n/2 << endl;
	for(int i=1;i<=n/2;i++){
		for(int j=i;j<=n/2;j++){
			cin >> s;
			sort(s.begin(),s.end());
			besar.push_back(s);
		}
	}
	cout << "? 2 " << n/2 << endl;
	for(int i=2;i<=n/2;i++){
		for(int j=i;j<=n/2;j++){
			cin >> s;
			sort(s.begin(),s.end());
			kecil.push_back(s);
		}
	}
	//sisa adalah bagian yang dari besar yang gaada di kecil
	sort(kecil.begin(),kecil.end());
	sort(besar.begin(),besar.end());
	int j=0;
	for(int i=0;i<kecil.size();i++){
		while(kecil[i]!=besar[j]){
			sisa.push_back(besar[j]);
			j++;
		}
		j++;
	}
	for(int i=j;i<besar.size();i++)sisa.push_back(besar[i]);
	sort(sisa.begin(),sisa.end(),cmp);
	string pref="",suf="";
	for(auto isi : sisa){
		for(int i=0;i<isi.length();i++)brp[isi[i]-'a']++;
		for(int i=0;i<26;i++){
			if(brp[i]>prv[i])pref+=(char)(i+'a');
		}
		for(int i=0;i<26;i++)prv[i]=brp[i];
		memset(brp,0,sizeof(brp));
	}
	cout << "? 1 " << n << endl;
	for(int i=1;i<=n;i++){
		for(int j=i;j<=n;j++){
			cin >> s;
			v[s.length()].push_back(s);
		}
	}
	for(int i=0;i<n;i++)brp[v[n][0][i]-'a']++;
	for(int i=1;i<=n/2;i++){
		besar.clear();
		//besar menyimpan komplemen dari substring yang panjangnya n-i -> komplemennya panjangnya i
		for(auto isi : v[n-i]){
			memset(prv,0,sizeof(prv));
			for(int j=0;j<n-i;j++)prv[isi[j]-'a']++;
			s="";
			for(int j=0;j<26;j++){
				for(int k=0;k<brp[j]-prv[j];k++)s+=((char)('a'+j));
			}
			besar.push_back(s);
		}
		//mau ngehapus sehingga sisa komplemen yang suffix
		kecil.clear();
		for(int j=1;j<=i;j++){
			//j di pref  i-j di suf
			s=pref.substr(0,j)+suf.substr(0,i-j);
			sort(s.begin(),s.end());
			kecil.push_back(s);
		}
		sort(kecil.begin(),kecil.end());
		sort(besar.begin(),besar.end());
		int idx=besar.size()-1;
		for(int j=0;j<kecil.size();j++){
			if(kecil[j]!=besar[j]){
				idx=j;
				break;
			}
		}
		//besar[idx] suffix
		memset(now,0,sizeof(now));
		for(int j=0;j<i;j++)now[besar[idx][j]-'a']++;
		for(int j=0;j<26;j++){
			if(now[j]>last[j]){
				suf+=(char)('a'+j);
				break;
			}
		}
		for(int j=0;j<26;j++)last[j]=now[j];
	}
	if(n&1){
		memset(now,0,sizeof(now));
		for(int i=0;i<pref.length();i++)now[pref[i]-'a']++;
		for(int i=0;i<suf.length();i++)now[suf[i]-'a']++;
		for(int i=0;i<26;i++){
			if(brp[i]>now[i]){
				pref+=(char)('a'+i);
				break;
			}
		}
	}
	reverse(suf.begin(),suf.end());
	cout << "! " << pref+suf << endl;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int Nmax = 105;

char ans[Nmax];
vector< pair<int, string> > v[Nmax];
vector<int> T;

int ap_lev[Nmax][30], ap[Nmax*Nmax][30];

int n;

///////////////////////////////////
queue<string> q;
string ST;

void do_query(int l, int r)
{
    cout << "? " << l << ' ' << r << endl;
    return;
    ///

    assert(q.empty());

    vector<string> all;

    int i, j;
    for(i=l; i<=r; ++i)
    {
        string s;
        for(j=i; j<=r; ++j)
        {
            s.push_back(ST[j]);
            all.push_back(s);
        }
    }

    for(auto &it : all)
        random_shuffle(it.begin(), it.end());

    random_shuffle(all.begin(), all.end());

    for(auto it : all)
        q.push(it);

    assert(all.size() == (r-l+1) * (r-l+2) / 2);
}

string next_string()
{
    string s;
    cin >> s;
    return s;
    ///

    string now = q.front();
    q.pop();
    return now;
}

//////////////////////////////////

void add_edge(int x, int y, string &now)
{
    v[x].push_back({ y, now });
    v[y].push_back({ x, now });
}

bool dfs(int node)
{
    T.push_back(node);

    for(auto it : v[node])
    {
        int to = it.first;
        string edg = it.second;

        if(ans[node] != edg[0] && ans[node] != edg[1]) return 0;

        if(!ans[to])
        {
            ans[to] = edg[0] + edg[1] - ans[node];
            if(!dfs(to)) return 0;
        }
        else if(ans[to] != edg[0] + edg[1] - ans[node]) return 0;
    }

    return 1;
}

void solve()
{
    int i;
    for(i=1; i<=n; ++i)
        if(!ans[i])
        {
            ans[i] = v[i][0].second[0];
            T.clear();

            if(dfs(i) == 0)
            {
                for(auto it : T) ans[it] = 0;

                ans[i] = v[i][0].second[1];
                T.clear();

                assert(dfs(i));
            }
        }
}

void query(int l, int r)
{
    if(l == r)
    {
        do_query(l, r);
        ans[l] = next_string()[0];
        return;
    }

    do_query(l, r);

    int i, j, id, k, len = r - l + 1;

    for(i = 1; i <= len * (len+1) / 2; ++i)
    {
        string s;
        s = next_string();

        for(auto it : s) ap[i][it - 'a'] ++;
        if(s.size() == len) id = i;
    }

    for(i=0; i<26; ++i)
        swap(ap[id][i], ap[len * (len+1) / 2][i]);
    id = len * (len+1) / 2;

    for(i = 1; i <= len * (len + 1) / 2; ++i)
        {
            int where = 0;
            for(j=0; j<26; ++j)
            {
                ap[i][j] = ap[id][j] - ap[i][j];
                where += ap[i][j];
            }

            for(j=0; j<26; ++j)
                ap_lev[where][j] += ap[i][j];
        }

    for(i=1; i<=len-i+1; ++i)
    {
        for(j=1; j<i; ++j)
            for(k=0; k<26; ++k)
                ap_lev[i][k] -= ap_lev[j][k] * (i - j + 1);

        string now;
        for(j=0; j<26; ++j)
            for(k=0; k<ap_lev[i][j]; ++k)
                now.push_back(j + 'a');

        add_edge(l + i - 1, r - i + 1, now);
    }

    for(i=0; i<=len * (len+1) / 2; ++i)
        for(j=0; j<26; ++j)
            ap_lev[i][j] = ap[i][j] = 0;
}

int main()
{
#ifndef ONLINE_JUDGE
   // freopen("input", "r", stdin);
#endif

    cin >> n;
  ///  cin >> ST; ST = '#' + ST;

    query(1, n);
    query(1, (n+1) / 2);
    query(n/2 + 1, n);

    solve();
    cout << "! " << (ans+1) << endl;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int Nmax = 105;

char ans[Nmax];
vector< pair<int, string> > v[Nmax];
vector<int> T;

int ap_lev[Nmax][30], ap[Nmax*Nmax][30];

int n;

///////////////////////////////////
queue<string> q;
string ST;

void do_query(int l, int r)
{
    assert(q.empty());

    vector<string> all;

    int i, j;
    for(i=l; i<=r; ++i)
    {
        string s;
        for(j=i; j<=r; ++j)
        {
            s.push_back(ST[j]);
            all.push_back(s);
        }
    }

    for(auto &it : all)
        random_shuffle(it.begin(), it.end());

    random_shuffle(all.begin(), all.end());

    for(auto it : all)
        q.push(it);

    assert(all.size() == (r-l+1) * (r-l+2) / 2);
}

string next_string()
{
    string now = q.front();
    q.pop();
    return now;
}

//////////////////////////////////

void add_edge(int x, int y, string &now)
{
    v[x].push_back({ y, now });
    v[y].push_back({ x, now });
}

bool dfs(int node)
{
    T.push_back(node);

    for(auto it : v[node])
    {
        int to = it.first;
        string edg = it.second;

        if(ans[node] != edg[0] && ans[node] != edg[1]) return 0;

        if(!ans[to])
        {
            ans[to] = edg[0] + edg[1] - ans[node];
            if(!dfs(to)) return 0;
        }
        else if(ans[to] != edg[0] + edg[1] - ans[node]) return 0;
    }

    return 1;
}

void solve()
{
    int i;
    for(i=1; i<=n; ++i)
        if(!ans[i])
        {
            ans[i] = v[i][0].second[0];
            T.clear();

            if(dfs(i) == 0)
            {
                for(auto it : T) ans[it] = 0;

                ans[i] = v[i][0].second[1];
                T.clear();

                assert(dfs(i));
            }
        }
}

void query(int l, int r)
{
     cout << "? " << l << ' ' << r << endl;
   /// do_query(l, r);

    int i, j, id, k, len = r - l + 1;

    for(i = 1; i <= len * (len+1) / 2; ++i)
    {
        string s;
        cin >> s;
        ///s = next_string();

        for(auto it : s) ap[i][it - 'a'] ++;
        if(s.size() == len) id = i;
    }

    for(i=0; i<26; ++i)
        swap(ap[id][i], ap[len * (len+1) / 2][i]);
    id = len * (len+1) / 2;

    for(i = 1; i <= len * (len + 1) / 2; ++i)
        {
            int where = 0;
            for(j=0; j<26; ++j)
            {
                ap[i][j] = ap[id][j] - ap[i][j];
                where += ap[i][j];
            }

            for(j=0; j<26; ++j)
                ap_lev[where][j] += ap[i][j];
        }

    for(i=1; i<=len-i+1; ++i)
    {
        for(j=1; j<i; ++j)
            for(k=0; k<26; ++k)
                ap_lev[i][k] -= ap_lev[j][k] * (i - j + 1);

        string now;
        for(j=0; j<26; ++j)
            for(k=0; k<ap_lev[i][j]; ++k)
                now.push_back(j + 'a');

        add_edge(l + i - 1, r - i + 1, now);
    }

    for(i=0; i<=len * (len+1) / 2; ++i)
        for(j=0; j<26; ++j)
            ap_lev[i][j] = ap[i][j] = 0;
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("input", "r", stdin);
#endif

    cin >> n;

    query(1, n);
    query(1, (n+1) / 2);
    query(n/2 + 1, n);

    solve();
    cout << (ans+1) << '\n';

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int Nmax = 105;
const bool EVAL = 1;

char ans[Nmax];
vector< pair<int, string> > v[Nmax];
vector<int> T;

int ap_lev[Nmax*Nmax][30], ap[Nmax*Nmax][30];

int n;

///////////////////////////////////
queue<string> q;
string ST;

int nr_crt;

void do_query(int l, int r)
{
    nr_crt += (r-l+1) * (r-l+2) / 2;

    if(EVAL == 1)
    {
        cout << "? " << l << ' ' << r << endl;
        return;
    }

    assert(q.empty());

    vector<string> all;

    int i, j;
    for(i=l; i<=r; ++i)
    {
        string s;
        for(j=i; j<=r; ++j)
        {
            s.push_back(ST[j]);
            all.push_back(s);
        }
    }

    for(auto &it : all)
        random_shuffle(it.begin(), it.end());

    random_shuffle(all.begin(), all.end());

    for(auto it : all)
        q.push(it);

    assert(all.size() == (r-l+1) * (r-l+2) / 2);
}

string next_string()
{
    if(EVAL == 1)
    {
        string s;
        cin >> s;
        return s;
    }

    string now = q.front();
    q.pop();
    return now;
}

//////////////////////////////////

void add_edge(int x, int y, string &now)
{
    if(x == y) ans[x] = now[0];
    v[x].push_back({ y, now });
    v[y].push_back({ x, now });
}

bool dfs(int node)
{
    T.push_back(node);

    for(auto it : v[node])
    {
        int to = it.first;
        string edg = it.second;

        if(ans[node] != edg[0] && ans[node] != edg[1]) return 0;

        if(!ans[to])
        {
            ans[to] = edg[0] + edg[1] - ans[node];
            if(!dfs(to)) return 0;
        }
        else if(ans[to] != edg[0] + edg[1] - ans[node]) return 0;
    }

    return 1;
}

void solve(int start)
{
    dfs(start);
}

void query(int l, int r)
{
    if(l == r)
    {
        do_query(l, r);
        ans[l] = next_string()[0];
        return;
    }

    do_query(l, r);

    int i, j, id, k, len = r - l + 1;

    for(i = 1; i <= len * (len+1) / 2; ++i)
    {
        string s;
        s = next_string();

        for(auto it : s) ap[i][it - 'a'] ++;
        if(s.size() == len) id = i;
    }

    for(i=0; i<26; ++i)
        swap(ap[id][i], ap[len * (len+1) / 2][i]);
    id = len * (len+1) / 2;

    for(i = 1; i <= len * (len + 1) / 2; ++i)
        {
            int where = 0;
            for(j=0; j<26; ++j)
            {
                ap[i][j] = ap[id][j] - ap[i][j];
                where += ap[i][j];
            }

            for(j=0; j<26; ++j)
                ap_lev[where][j] += ap[i][j];
        }

    for(i=1; i<=len-i+1; ++i)
    {
        for(j=1; j<i; ++j)
            for(k=0; k<26; ++k)
                ap_lev[i][k] -= ap_lev[j][k] * (i - j + 1);

        string now;
        for(j=0; j<26; ++j)
            for(k=0; k<ap_lev[i][j]; ++k)
                now.push_back(j + 'a');

        add_edge(l + i - 1, r - i + 1, now);
    }

    for(i=0; i<=len * (len+1) / 2; ++i)
        for(j=0; j<26; ++j)
            ap_lev[i][j] = ap[i][j] = 0;
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("input", "r", stdin);
#endif

    cin >> n;
    if(EVAL == 0)
    {
        cin >> ST; ST = '#' + ST;
    }

    if(n == 1)
    {
        do_query(1, 1);
        cout << "! " << next_string() << endl;
        return 0;
    }

    query(1, n);
    if(n % 2 == 1)
    {
        query(1, n/2+1);
        query(n/2+2, n);
        solve(n/2+1);
    }
    else if(n % 2 == 0)
    {
        query(1, n/2+1);
        query(n/2+1, n);

        if(n % 4 == 0) solve(n/4 + 1);
            else solve( (3 * n + 2) / 4);
    }

    cout << "! " << (ans+1) << endl;
    if(EVAL == 0) cout << nr_crt << ' ' << ((n+1) * (n+1) * 3 + 3) / 4 << '\n';

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int Nmax = 105;
const bool EVAL = 1;

char ans[Nmax];
vector< pair<int, string> > v[Nmax];
vector<int> T;

int ap_lev[Nmax*Nmax][30], ap[Nmax*Nmax][30];

int n;

///////////////////////////////////
queue<string> q;
string ST;

void do_query(int l, int r)
{
    if(EVAL == 1)
    {
        cout << "? " << l << ' ' << r << endl;
        return;
    }

    assert(q.empty());

    vector<string> all;

    int i, j;
    for(i=l; i<=r; ++i)
    {
        string s;
        for(j=i; j<=r; ++j)
        {
            s.push_back(ST[j]);
            all.push_back(s);
        }
    }

    for(auto &it : all)
        random_shuffle(it.begin(), it.end());

    random_shuffle(all.begin(), all.end());

    for(auto it : all)
        q.push(it);

    assert(all.size() == (r-l+1) * (r-l+2) / 2);
}

string next_string()
{
    if(EVAL == 1)
    {
        string s;
        cin >> s;
        return s;
    }

    string now = q.front();
    q.pop();
    return now;
}

//////////////////////////////////

void add_edge(int x, int y, string &now)
{
    v[x].push_back({ y, now });
    v[y].push_back({ x, now });
}

bool dfs(int node)
{
    T.push_back(node);

    for(auto it : v[node])
    {
        int to = it.first;
        string edg = it.second;

        if(ans[node] != edg[0] && ans[node] != edg[1]) return 0;

        if(!ans[to])
        {
            ans[to] = edg[0] + edg[1] - ans[node];
            if(!dfs(to)) return 0;
        }
        else if(ans[to] != edg[0] + edg[1] - ans[node]) return 0;
    }

    return 1;
}

void solve()
{
    int i;
    for(i=1; i<=n; ++i)
        if(!ans[i])
        {
            ans[i] = v[i][0].second[0];
            T.clear();

            if(dfs(i) == 0)
            {
                for(auto it : T) ans[it] = 0;

                ans[i] = v[i][0].second[1];
                T.clear();

                assert(dfs(i));
            }
        }
}

void query(int l, int r)
{
    if(l == r)
    {
        do_query(l, r);
        ans[l] = next_string()[0];
        return;
    }

    do_query(l, r);

    int i, j, id, k, len = r - l + 1;

    for(i = 1; i <= len * (len+1) / 2; ++i)
    {
        string s;
        s = next_string();

        for(auto it : s) ap[i][it - 'a'] ++;
        if(s.size() == len) id = i;
    }

    for(i=0; i<26; ++i)
        swap(ap[id][i], ap[len * (len+1) / 2][i]);
    id = len * (len+1) / 2;

    for(i = 1; i <= len * (len + 1) / 2; ++i)
        {
            int where = 0;
            for(j=0; j<26; ++j)
            {
                ap[i][j] = ap[id][j] - ap[i][j];
                where += ap[i][j];
            }

            for(j=0; j<26; ++j)
                ap_lev[where][j] += ap[i][j];
        }

    for(i=1; i<=len-i+1; ++i)
    {
        for(j=1; j<i; ++j)
            for(k=0; k<26; ++k)
                ap_lev[i][k] -= ap_lev[j][k] * (i - j + 1);

        string now;
        for(j=0; j<26; ++j)
            for(k=0; k<ap_lev[i][j]; ++k)
                now.push_back(j + 'a');

        add_edge(l + i - 1, r - i + 1, now);
    }

    for(i=0; i<=len * (len+1) / 2; ++i)
        for(j=0; j<26; ++j)
            ap_lev[i][j] = ap[i][j] = 0;
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("input", "r", stdin);
#endif

    cin >> n;
    if(EVAL == 0)
    {
        cin >> ST; ST = '#' + ST;
    }

    query(1, n);
    query(1, (n+1) / 2);
    query(n/2 + 1, n);

    solve();
    cout << "! " << (ans+1) << endl;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int Nmax = 105;

char ans[Nmax];
vector< pair<int, string> > v[Nmax];
vector<int> T;

int ap_lev[Nmax][30], ap[Nmax*Nmax][30];

int n;

///////////////////////////////////
queue<string> q;
string ST;

void do_query(int l, int r)
{
    assert(q.empty());

    vector<string> all;

    int i, j;
    for(i=l; i<=r; ++i)
    {
        string s;
        for(j=i; j<=r; ++j)
        {
            s.push_back(ST[j]);
            all.push_back(s);
        }
    }

    for(auto &it : all)
        random_shuffle(it.begin(), it.end());

    random_shuffle(all.begin(), all.end());

    for(auto it : all)
        q.push(it);

    assert(all.size() == (r-l+1) * (r-l+2) / 2);
}

string next_string()
{
    string now = q.front();
    q.pop();
    return now;
}

//////////////////////////////////

void add_edge(int x, int y, string &now)
{
    v[x].push_back({ y, now });
    v[y].push_back({ x, now });
}

bool dfs(int node)
{
    T.push_back(node);

    for(auto it : v[node])
    {
        int to = it.first;
        string edg = it.second;

        if(ans[node] != edg[0] && ans[node] != edg[1]) return 0;

        if(!ans[to])
        {
            ans[to] = edg[0] + edg[1] - ans[node];
            if(!dfs(to)) return 0;
        }
        else if(ans[to] != edg[0] + edg[1] - ans[node]) return 0;
    }

    return 1;
}

void solve()
{
    int i;
    for(i=1; i<=n; ++i)
        if(!ans[i])
        {
            ans[i] = v[i][0].second[0];
            T.clear();

            if(dfs(i) == 0)
            {
                for(auto it : T) ans[it] = 0;

                ans[i] = v[i][0].second[1];
                T.clear();

                assert(dfs(i));
            }
        }
}

void query(int l, int r)
{
     cout << "? " << l << ' ' << r << endl;
   /// do_query(l, r);

    int i, j, id, k, len = r - l + 1;

    for(i = 1; i <= len * (len+1) / 2; ++i)
    {
        string s;
        cin >> s;
        ///s = next_string();

        for(auto it : s) ap[i][it - 'a'] ++;
        if(s.size() == len) id = i;
    }

    for(i=0; i<26; ++i)
        swap(ap[id][i], ap[len * (len+1) / 2][i]);
    id = len * (len+1) / 2;

    for(i = 1; i <= len * (len + 1) / 2; ++i)
        {
            int where = 0;
            for(j=0; j<26; ++j)
            {
                ap[i][j] = ap[id][j] - ap[i][j];
                where += ap[i][j];
            }

            for(j=0; j<26; ++j)
                ap_lev[where][j] += ap[i][j];
        }

    for(i=1; i<=len-i+1; ++i)
    {
        for(j=1; j<i; ++j)
            for(k=0; k<26; ++k)
                ap_lev[i][k] -= ap_lev[j][k] * (i - j + 1);

        string now;
        for(j=0; j<26; ++j)
            for(k=0; k<ap_lev[i][j]; ++k)
                now.push_back(j + 'a');

        add_edge(l + i - 1, r - i + 1, now);
    }

    for(i=0; i<=len * (len+1) / 2; ++i)
        for(j=0; j<26; ++j)
            ap_lev[i][j] = ap[i][j] = 0;
}

int main()
{
#ifndef ONLINE_JUDGE
  //  freopen("input", "r", stdin);
#endif

    cin >> n;

    query(1, n);
    query(1, (n+1) / 2);
    query(n/2 + 1, n);

    solve();
    cout << "! " << (ans+1) << endl;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int Nmax = 105;
const bool EVAL = 1;

char ans[Nmax];
vector< pair<int, string> > v[Nmax];
vector<int> T;

int ap_lev[Nmax*Nmax][30], ap[Nmax*Nmax][30];

int n;

///////////////////////////////////
queue<string> q;
string ST;

void do_query(int l, int r)
{
    if(EVAL == 1)
    {
        cout << "? " << l << ' ' << r << endl;
        return;
    }

    assert(q.empty());

    vector<string> all;

    int i, j;
    for(i=l; i<=r; ++i)
    {
        string s;
        for(j=i; j<=r; ++j)
        {
            s.push_back(ST[j]);
            all.push_back(s);
        }
    }

    for(auto &it : all)
        random_shuffle(it.begin(), it.end());

    random_shuffle(all.begin(), all.end());

    for(auto it : all)
        q.push(it);

    assert(all.size() == (r-l+1) * (r-l+2) / 2);
}

string next_string()
{
    if(EVAL == 1)
    {
        string s;
        cin >> s;
        return s;
    }

    string now = q.front();
    q.pop();
    return now;
}

//////////////////////////////////

void add_edge(int x, int y, string &now)
{
    v[x].push_back({ y, now });
    v[y].push_back({ x, now });
}

bool dfs(int node)
{
    T.push_back(node);

    for(auto it : v[node])
    {
        int to = it.first;
        string edg = it.second;

        if(ans[node] != edg[0] && ans[node] != edg[1]) return 0;

        if(!ans[to])
        {
            ans[to] = edg[0] + edg[1] - ans[node];
            if(!dfs(to)) return 0;
        }
        else if(ans[to] != edg[0] + edg[1] - ans[node]) return 0;
    }

    return 1;
}

void solve()
{
    int i;
    for(i=1; i<=n; ++i)
        if(!ans[i])
        {
            ans[i] = v[i][0].second[0];
            T.clear();

            if(dfs(i) == 0)
            {
                for(auto it : T) ans[it] = 0;

                ans[i] = v[i][0].second[1];
                T.clear();

                assert(dfs(i));
            }
        }
}

void query(int l, int r)
{
    if(l == r)
    {
        do_query(l, r);
        ans[l] = next_string()[0];
        return;
    }

    do_query(l, r);

    int i, j, id, k, len = r - l + 1;

    for(i = 1; i <= len * (len+1) / 2; ++i)
    {
        string s;
        s = next_string();

        for(auto it : s) ap[i][it - 'a'] ++;
        if(s.size() == len) id = i;
    }

    for(i=0; i<26; ++i)
        swap(ap[id][i], ap[len * (len+1) / 2][i]);
    id = len * (len+1) / 2;

    for(i = 1; i <= len * (len + 1) / 2; ++i)
        {
            int where = 0;
            for(j=0; j<26; ++j)
            {
                ap[i][j] = ap[id][j] - ap[i][j];
                where += ap[i][j];
            }

            for(j=0; j<26; ++j)
                ap_lev[where][j] += ap[i][j];
        }

    for(i=1; i<=len-i+1; ++i)
    {
        for(j=1; j<i; ++j)
            for(k=0; k<26; ++k)
                ap_lev[i][k] -= ap_lev[j][k] * (i - j + 1);

        string now;
        for(j=0; j<26; ++j)
            for(k=0; k<ap_lev[i][j]; ++k)
                now.push_back(j + 'a');

        add_edge(l + i - 1, r - i + 1, now);
    }

    for(i=0; i<=len * (len+1) / 2; ++i)
        for(j=0; j<26; ++j)
            ap_lev[i][j] = ap[i][j] = 0;
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("input", "r", stdin);
#endif

    cin >> n;
    cin >> ST; ST = '#' + ST;

    query(1, n);
    query(1, (n+1) / 2);
    query(n/2 + 1, n);

    solve();
    cout << "! " << (ans+1) << endl;

    return 0;
}