#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdio>
#include <iomanip>
#include <fstream>
#include <cassert>
#include <cstring>
#include <unordered_set>
#include <unordered_map>
#include <numeric>
#include <ctime>
#include <bitset>
#include <complex>
#include <chrono>
#include <random>
#include <functional>

using namespace std;

const bool DEBUG = 0;

vector<vector<int>> a;

int n, m;
int qcnt = 0;

int lg(int x) {
    int c = 1;
    int ans = 0;
    while (2 * c <= x) {
        c *= 2;
        ans++;
    }
    return ans;
}

int query(int f, int s, int i1, int j1, int i2, int j2) {
    qcnt++;
    assert(qcnt <= 3 * lg(n + m));
    if (f == 0 || s == 0) return 1;
    if (DEBUG) {
        int ok = 1;
        vector<vector<int>> cnt(n, vector<int> (m));
        for (int i = 0; i < f; i++) {
            for (int j = 0; j < s; j++) {
                assert(i1 + i < n && i2 + i < n);
                assert(j1 + j < m && j2 + j < m);
                ok &= (a[i1 + i][j1 + j] == a[i2 + i][j2 + j]);
                cnt[i1 + i][j1 + j]++;
                cnt[i2 + i][j2 + j]++;
                assert(cnt[i1 + i][j1 + j] == 1);
                assert(cnt[i2 + i][j2 + j] == 1);
            }
        }
        return ok;
    } else {
        cout << "? " << f << ' ' << s << ' ' << i1 + 1 << ' ' << j1 + 1 << ' ' << i2 + 1 << ' ' << j2 + 1 << endl;
        int res;
        cin >> res;
        return res;
    }
}

int check_h(int d) {
    int cnt = m / d;
    if (cnt & 1) {
        int mid = d * (cnt / 2);
        return query(n, d * (cnt / 2), 0, 0, 0, mid) && query(n, d * (cnt / 2), 0, 0, 0, mid + d);
    } else {
        int mid = d * (cnt / 2);
        return query(n, d * (cnt / 2), 0, 0, 0, mid) && query(n, d * (cnt / 2 - 1), 0, 0, 0, mid + d);
    }
}

int check_v(int d) {
    int cnt = n / d;
    if (cnt & 1) {
        int mid = d * (cnt / 2);
        return query(d * (cnt / 2), m, 0, 0, mid, 0) && query(d * (cnt / 2), m, 0, 0, mid + d, 0);
    } else {
        int mid = d * (cnt / 2);
        return query(d * (cnt / 2), m, 0, 0, mid, 0) && query(d * (cnt / 2 - 1), m, 0, 0, mid + d, 0);
    }
}

int solve_v() {
    vector<int> primes;
    int wn = n;
    for (int i = 2; i <= n; i++) {
        int c = 0;
        while (wn % i == 0) {
            c++;
            wn /= i;
        }
        if (c) {
            primes.push_back(i);
        }
    }
    int cur = n;
    for (auto t : primes) {
        int cnt_in = 0;
        int ncur = cur;
        while (ncur % t == 0) {
            cnt_in++;
            ncur /= t;
        }
        int l = 0;
        int r = cnt_in + 1;
        while (r - l > 1) {
            int mid = (r + l) / 2;
            ncur = cur;
            for (int i = 0; i < mid; i++) {
                ncur /= t;
            }
            if (check_v(ncur)) {
                l = mid;
            } else {
                r = mid;
            }
        }
        for (int i = 0; i < l; i++) {
            cur /= t;
        }
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        ans += (n % i == 0 && i % cur == 0);
    }
    return ans;
}

int solve_h() {
    vector<int> primes;
    int wm = m;
    for (int i = 2; i <= m; i++) {
        int c = 0;
        while (wm % i == 0) {
            c++;
            wm /= i;
        }
        if (c) {
            primes.push_back(i);
        }
    }
    int cur = m;
    for (auto t : primes) {
        int cnt_in = 0;
        int ncur = cur;
        while (ncur % t == 0) {
            cnt_in++;
            ncur /= t;
        }
        int l = 0;
        int r = cnt_in + 1;
        while (r - l > 1) {
            int mid = (r + l) / 2;
            ncur = cur;
            for (int i = 0; i < mid; i++) {
                ncur /= t;
            }
            if (check_h(ncur)) {
                l = mid;
            } else {
                r = mid;
            }
        }
        for (int i = 0; i < l; i++) {
            cur /= t;
        }
    }
    int ans = 0;
    for (int i = 1; i <= m; i++) {
        ans += (m % i == 0 && i % cur == 0);
    }
    return ans;
}

mt19937 rng(10);

void run(int n_, int m_) {
    n = n_;
    m = m_;
    qcnt = 0;
    solve_h();
    solve_v();
    assert(qcnt <= 3 * lg(n + m));
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);

    // cerr << 3 * lg(2000) << endl;

    if (DEBUG) {
        a.resize(1000, vector<int> (1000));
        while (true) {
            cerr << "test " << endl;
            run(rng() % 1000 + 1, rng() % 1000 + 1);
        }
    } else {
        cin >> n >> m;
        int f = solve_h();
        int s = solve_v();
        cout << "! " << f * s << endl;
        exit(0);
    }

}
