DP
数字从大到小填,小的数字只能填在有大的数的行或者列中。 dp[i][j][k] 表示的状态是填完第i个数后,有i行j列被占用,填下一个数的时候只能填在这些被大的数占用的行或者列当中。考虑的情况有3种:
- 在列的基础上占据一个新的行。
- 在行的基础上占据一个新的列。
- 在不增加新列和新行的情况下填一个数。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int dp[85*85][85][85];
int main(void)
{
int T;
scanf("%d", &T);
while(T--) {
int n, m, mod;
scanf("%d%d%d", &n, &m, &mod);
memset(dp, 0, sizeof(dp));
dp[1][1][1] = n*m;
for(int i = 2; i <= n*m; ++i) {
for(int j = 1; j <= n; ++j) {
for(int k = 1; k <= m; ++k) {
if(j*k >= i) {
if(dp[i-1][j-1][k])
dp[i][j][k] = ((long long)dp[i-1][j-1][k]*(n-(j-1))*k)%mod;
if(dp[i-1][j][k-1])
dp[i][j][k] = (dp[i][j][k]+(long long)dp[i-1][j][k-1]*(m-(k-1))*j)%mod;
if(dp[i-1][j][k])
dp[i][j][k] = (dp[i][j][k]+(long long)dp[i-1][j][k]*(j*k-i+1))%mod;
}
}
}
}
printf("%d\n", dp[n*m][n][m]);
}
return 0;
}
浙公网安备 33010602011771号