#include<bits/stdc++.h>

using namespace std;

int N = 50, M = 50, mod, a[109][109];
int DBG = 0;

namespace localTester {
    int s[109][109], a[109][109];
    void init (int overall)
    {
        if (DBG == 1)
        {
            memset (a, 0, sizeof (a));
            memset (s, 0, sizeof (s));
            int nr = 0, x[N * M + 1], y[N * M + 1];
            for (int i=1; i<=N; i++)
                for (int j=1; j<=M; j++)
                    x[++nr] = i, y[nr] = j;
            bool type[nr + 1];
            for (int i=1; i<=nr; i++)
                type[i] = (i <= overall);
            random_shuffle (type + 1, type + nr + 1);
            for (int i=1; i<=nr; i++)
                if (type[i])
                    a[x[i]][y[i]] = s[x[i]][y[i]] = 1;
        }
        else
        if (DBG == 2)
        {
            for (int i=1; i<=N; i++)
                for (int j=1; j<=M; j++)
                    scanf ("%d", &a[i][j]), s[i][j] = a[i][j];
        }
        for (int i=1; i<=N; i++)
            for (int j=1; j<=M; j++)
                s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
    }
    int query (int a1, int b1, int a2, int b2)
    {
        return s[a2][b2] - s[a1 - 1][b2] - s[a2][b1 - 1] + s[a1 - 1][b1 - 1];
    }
}

int queries = 0;
int query (int a1, int b1, int a2, int b2)
{
    queries ++;
    if (DBG) return localTester::query (a1, b1, a2, b2);
    printf ("? %d %d %d %d\n", a1 - 1, b1 - 1, a2 - 1, b2 - 1);
    fflush (stdout);
    int x;
    scanf ("%d", &x);
    return x;
}

//int lg[109];
int lg[]={0,1,1,2,2,4,4,4,4,8,8,8,4,5,2,4,4,5,8,11,14,11,6,7,16,13,10,15,24,1,16,8,16,1,2,3,28,1,22,7,8,10,36,8,6,29,22,24,8,18,18};
int getMid (int a, int b)
{
    if (rand () & 1)
        return a + lg[b - a + 1] - 1;
    else
        return b - lg[b - a + 1];
    return (a + b) / 2;
//    return a + rand () % (b - a + 1);
}

void solve (int a1, int b1, int a2, int b2, int sum)
{
    if (sum == 0 || sum == (a2 - a1 + 1) * (b2 - b1 + 1))
    {
        for (int i=a1; i<=a2; i++)
            for (int j=b1; j<=b2; j++)
                a[i][j] = (sum > 0);
        return ;
    }
    if (a2 - a1 < b2 - b1)
    {
        int mid = getMid (b1, b2), s0 = query (a1, b1, a2, mid);
        solve (a1, b1, a2, mid, s0);
        solve (a1, mid + 1, a2, b2, sum - s0);
    }
    else
    {
        int mid = getMid (a1, a2), s0 = query (a1, b1, mid, b2);
        solve (a1, b1, mid, b2, s0);
        solve (mid + 1, b1, a2, b2, sum - s0);
    }
}

void finish ()
{
    if (DBG)
    {
        for (int i=1; i<=N; i++)
            for (int j=1; j<=M; j++)
                if (localTester::a[i][j] != a[i][j])
                {
                    printf ("WA\n");
                    exit (0);
                }
        printf ("OK %d\n", queries);
        //exit (0);
    }
    int p2[N * M + 10], ans = 0;
    p2[0] = 1;
    for (int i=1; i<=N * M; i++)
        p2[i] = (p2[i - 1] + p2[i - 1]) % mod;
    for (int i=0; i<N; i++)
        for (int j=0; j<M; j++)
            if (a[i + 1][j + 1])
                ans = (ans + p2[i * M + j]) % mod;
    printf ("! %d\n", ans);
/*    for (int i=1; i<=N; i++, printf ("\n"))
        for (int j=1; j<=M; j++)
            printf ("%d", a[i][j]);*/
    fflush (stdout);
}

double averageTrying (int overall)
{
    int steps = 50;
    double sum = 0;
    while (steps --)
    {
        localTester::init (overall), queries = 0;
        for (int i=1; i<=N; i++)
        {
            int curr;
            if (i < N) curr = query (i, 1, i, M), overall -= curr;
            else curr = overall;
            solve (i, 1, i, M, curr);
        }
        sum += queries;
    }
    sum /= 50.0;
    return sum;
}

double dp[109];
int main ()
{
//freopen ("input", "r", stdin);
//freopen ("output", "w", stdout);

srand (time (0));
/*int j = 1;
for (int i=1; i<=10; i++)
{
    while (2 * j < i)
        j += j;
    lg[i] = j;
}
for (int L=10; L<=50; L++)
{
    int how = -1;
    dp[L] = 10000000.0;
    for (int i=1; i<L; i++)
    {
        lg[L] = i, N = M = L;
        double curr = averageTrying (L * L / 10);
        if (curr < dp[L])
            dp[L] = curr, how = i;
    }
    lg[L] = how;
}
printf ("%.10f\n", dp[50]);
printf ("lg={0");
for (int i=1; i<=50; i++)
    printf (",%d", lg[i]);
printf ("};\n");
return 0;*/
/*if (DBG > 0)
{
    //lg[50] = 40, lg[40] = 30, lg[30] = 20, lg[20] = 10;
    printf ("%.5f\n", averageTrying (250));
    return 0;
}*/
int overall;
if (DBG == 0)
    scanf ("%d %d %d %d", &N, &M, &overall, &mod);
localTester::init (overall);
//solve (1, 1, N, M, overall);
for (int i=1; i<=N; i++)
{
    int curr;
    if (i < N) curr = query (i, 1, i, M), overall -= curr;
    else curr = overall;
    solve (i, 1, i, M, curr);
}
finish ();

return 0;
}


Measured memory_bytes: 720