#include <bits/stdc++.h>

using namespace std ;

const int MAX_N = 1e3 + 1 ;
int spf[MAX_N], n, m;
void sieve(){ 
  spf[1] = 1; 
  for(int i=2; i < MAX_N; i++){
    spf[i] = i ; 
  }
  for(int i=4; i < MAX_N; i+=2){
    spf[i] = 2;
  } 
  for(int i=3; i*i < MAX_N; i++){ 
    if(spf[i] == i){ 
      for(int j=i*i; j < MAX_N; j+=i){
        if(spf[j] == j) spf[j] = i ; 
      }
    } 
  } 
} 
 
vector<pair<int,int> > PrimeFactors(int N){ 
  vector<pair<int,int> > v ;
  int curr = spf[N] ;   
  int cnt = 1 ;   
  while(N > 1){ 
    N /= spf[N]; 
    if(curr == spf[N]){ 
      cnt++ ; continue ; 
    } 
    v.push_back({curr,cnt}); 
	  curr = spf[N] ; cnt = 1 ; 
  } 
  return v ;
} 
bool query(int h,int w,int i1,int j1,int i2,int j2){
	cout << "? " << h << " " << w << " " << i1 << " " << j1 << " " << i2 << " " << j2 << endl ;
	int t; cin >> t; return t;  
}
bool HELP_N(int row,int parts){
	int len = row/parts;
	while(2*len <= row)
		if(!query(len,m,1,1,1+len,1)) return false ;
		else	len *= 2;
	if(len == row) return true ;
	return query(row - len, m, 2 * len - row + 1, 1, len + 1, 1);
}

bool HELP_M(int column,int parts){
	int len = column/parts;
	while(2*len <= column)
		if(!query(n,len,1,1,1,1+len)) return false ;
		else	len *= 2;
	if(len == column) return true ;
	return query(n, column - len, 1, 2 * len - column + 1, 1, len + 1);
}
signed main(){
  sieve(); 
  cin >> n >> m;
  int possible = 1;
  auto v = PrimeFactors(n) ;
  for(auto [prime,exponent]:v){
  	int row = n, cnt = 0;
  	for(int i = 1; i <= exponent; i++)
  		if(HELP_N(row,prime))
  			row /= prime , cnt++;
  		else
  			break;
  	possible *= (cnt + 1);
  }
  v = PrimeFactors(m) ;
  for(auto [prime,exponent]:v){
  	int column = m, cnt = 0;
  	for(int i = 1; i <= exponent; i++)
  		if(HELP_M(column,prime))
  			column /= prime , cnt++;
  		else
  			break;
  	possible *= (cnt + 1);
  }
  cout << "! " << possible << endl ;
}




