Problem:
Score : 2000 points

Problem Statement

For each of the K^{NM} ways to write an integer between 1 and K (inclusive) in every square in a square grid with N rows and M columns, find the value defined below, then compute the sum of all those K^{NM} values, modulo D.

For each of the NM squares, find the minimum among the N+M-1 integers written in the square's row or the square's column. The value defined for the grid is the product of all these NM values.

Constraints

1 \leq N,M,K \leq 100

10^8 \leq D \leq 10^9

N,M,K, and D are integers.

D is prime.

Input

Input is given from Standard Input in the following format:

N M K D

Output

Print the sum of the K^{NM} values, modulo D.

Sample Input 1

2 2 2 998244353

Sample Output 1

35

We have 1 way to write integers such that the product of the NM values is 16, 4 ways such that the product is 2, and 11 ways such that the product is 1.

Sample Input 2

2 3 4 998244353

Sample Output 2

127090

Sample Input 3

31 41 59 998244353

Sample Output 3

827794103

Solution in C++14 (GCC 5.4.1) (judge verdict: Accepted)

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

#define For(x,y,z) for(int x=y;x<=z;++x)

const int N = 101;
int pw[N][N*N], fac[N], inv[N];
int f[N][N], g[N][N], coe[N][N];
int n, m, K, p;

inline int qpow(int A, int B) {
	int r = 1; while(B) {
		if(B&1) r = (ll)r * A%p;
		A = (ll)A * A%p, B >>= 1;
	} return r;
}

int main() {
	scanf("%d%d%d%d", &n, &m, &K, &p);
	
	for(int i = 0; i <= K; ++ i) {
		pw[i][0] = 1;
		for(int j = 1; j <= n * m; ++ j)
			pw[i][j] = (ll)pw[i][j-1] * i%p;
	}
	
	int t = n;
	if(n < m) t = m;
	fac[0] = 1;
	for(int i = 1; i <= t; ++ i) fac[i] = (ll)fac[i-1] * i%p;
	inv[t] = qpow(fac[t], p-2);
	for(int i = t; i; -- i) inv[i-1] = (ll)inv[i] * i%p;
	
	g[0][0] = 1;
	For(t, 1, K) {
		swap(f, g);
		For(i, 0, n) For(j, 0, m)
			coe[i][j] = (ll)pw[t][i*(m-j)] * pw[K-t+1][i*j]%p * inv[i]%p;
		For(i, 0, n) For(j, 0, m) {
			int&v = g[i][j]; v = 0;
			For(k, 0, i)
				v = (v + (ll)f[i-k][j] * coe[k][j])%p;
		}
		/* definited row*/
		
		swap(f, g);
		For(i, 0, n) For(j, 0, m)
			coe[i][j] = (ll)pw[t][j*(n-i)] * pw[K-t+1][i*j]%p * inv[j]%p;
		For(i, 0, n) For(j, 0, m) {
			int&v = g[i][j]; v = 0;
			For(k, 0, j)
				v = (v + (ll)f[i][j-k] * coe[i][k])%p;
		}
		/* definited column */
		
		swap(f, g);
		For(i, 0, n) For(j, 0, m) {
			coe[i][j] = (ll)pw[t][i*(m-j)] * pw[K-t][i*j]%p * inv[i]%p;
			if(i&1) coe[i][j] = (ll)coe[i][j] * (p-1)%p;
		}
		For(i, 0, n) For(j, 0, m) {
			int&v = g[i][j]; v = 0;
			For(k, 0, i)
				v = (v + (ll)f[i-k][j] * coe[k][j])%p;
		}
		
		swap(f, g);
		For(i, 0, n) For(j, 0, m) {
			coe[i][j] = (ll)pw[t][j*(n-i)] * pw[K-t][i*j]%p * inv[j]%p;
			if(j&1) coe[i][j] = (ll)coe[i][j] * (p-1)%p;
		}
		For(i, 0, n) For(j, 0, m) {
			int&v = g[i][j]; v = 0;
			For(k, 0, j)
				v = (v + (ll)f[i][j-k] * coe[i][k])%p;
		}
	}
	
	printf("%lld\n", (ll)f[n][m] * fac[n]%p * fac[m]%p);
	return 0;
}