题目大意
现在满足要求的带权矩阵定义为至少有一个鞍点的矩阵。鞍点定义为在同一行和同一列都是严格最大的格点。
先在要求你求出大小为
解题思路
这种计数问题的关键就是设出不会算重算漏的状态。我们可以设状态
那么我们考虑
绿色部分为已已经放好的部分
那么最后的转移方程就是:
最后对于每个已经更新完的
容斥原理:当
当
程序
//YxuanwKeith
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 2005;
int N, M, K, Mo, Min, Max, C[MAXN][MAXN], Fac[MAXN * MAXN], F[MAXN][11], Pow[11][MAXN * MAXN];
void Prepare() {
C[0][0] = 1;
for (int i = 1; i <= Max; i ++) {
C[i][0] = 1;
for (int j = 1; j <= Max; j ++)
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % Mo;
}
Fac[0] = 1;
for (int i = 1; i <= N * M; i ++) Fac[i] = 1ll * Fac[i - 1] * i % Mo;
Pow[0][0] = 1;
for (int i = 1; i <= K; i ++) {
Pow[i][0] = 1;
for (int j = 1; j <= N * M; j ++) Pow[i][j] = 1ll * Pow[i][j - 1] * i % Mo;
}
}
void Solve() {
F[0][0] = 1;
for (int i = 0; i <= Min; i ++)
for (int j = 0; j < K; j ++) {
if (F[i][j] == 0) continue;
for (int x = 0; x <= Min - i; x ++)
F[i + x][j + 1] = (1ll * F[i + x][j + 1] + 1ll * F[i][j] * C[N - i][x] % Mo * C[M - i][x] % Mo * Fac[x] % Mo * Pow[j][x * (N - i) + x * (M - i) - x * x - x] % Mo) % Mo;
}
int Ans = 0;
for (int i = 1; i <= Min; i ++)
Ans = ((Ans + ((i & 1) ? 1ll : -1ll) * F[i][K] % Mo * Pow[K][(N - i) * (M - i)] % Mo) + Mo) % Mo;
printf("%d\n", Ans);
}
int main() {
scanf("%d%d%d%d", &N, &M, &K, &Mo);
Min = min(N, M), Max = max(N, M);
Prepare();
Solve();
}