//Author: RingweEH
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define db double
using namespace std;
int min( int a,int b ) { return a<b ? a : b; }
int max( int a,int b ) { return a>b ? a : b; }
void bmax( int &a,int b ) { a=(a>b) ? a : b; }
void bmin( int &a,int b ) { a=(a<b) ? a : b; }
int read()
{
    int x=0,w=1; char ch=getchar();
    while ( ch>'9' || ch<'0' ) { if ( ch=='-' ) w=-1; ch=getchar(); }
    while ( ch<='9' && ch>='0' ) x=x*10+ch-'0',ch=getchar();
    return x*w;
}

const int N=1e5+10;
int n,m,a[N],b[N],cnt;
bool fl;

int Query( int len,int p1,int p2 )	//查询整行/整列，另一维长为len，端点p1p2是否相等
{
	if ( !fl ) printf("? %d %d %d %d %d %d\n",len,m,p1,1,p2,1 );
	else printf("? %d %d %d %d %d %d\n",n,len,1,p1,1,p2 );
	fflush(stdout); int x=read(); return x;
}

//块长是len，分成divi个块，是否相等
bool Check( int len,int divi )
{
	if ( divi==2 ) return Query(len/2,1,len/2+1 );
	int x=len/divi*(divi/2);
	return Query(x,1,x+1) && Query(x,1,x+len/divi+1);
}

//对行/列计算能分的最大块数
int Work( int x )
{
	cnt=0; int nw=x;
	for ( int i=2; i<=nw; i++ )
		if ( nw%i==0 )
		{
			a[++cnt]=i,b[cnt]=0;
			while ( nw%i==0 ) b[cnt]++,nw/=i;
		}
	int res=1;
	for ( int i=1; i<=cnt; i++ )
		for ( int j=1; j<=b[i]; j++ )
			if ( Check(x/res,a[i]) ) res*=a[i];
			else break;
	return res;
}

int Count( int x )
{
	int res=0;
	for ( int i=1; i<=x; i++ ) res+=(x%i==0);
	return res;
}

int main()
{
//freopen( "exam.in","r",stdin );

	n=read(); m=read();
	int ans1=Work(n); fl=1;
	int ans2=Work(m);
	printf("! %d\n",Count(ans1)*Count(ans2) );

	return 0;
}