题意很简单,问有多少个nm的矩阵,元素是1~nm的排列,且只有一个元素比它所在行与列的所有元素都大。
很容易发现,由于是一个排列,那个满足条件的元素肯定是n*m,通过比划可以发现应从大到小把元素塞入矩阵,新塞入的元素的行或列至少有一个比它大的元素,于是就想到了用动态规划来转移。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,t;
int dp[82*82][85][85];
int k;
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&k);
dp[1][1][1]=n*m%k;
for(int i=2;i<=n*m;i++)
{
for(int j=1;j<=(min(i,n));j++)
{
for(int w=1;w<=(min(i,m));w++)
{
if(j*w<i) continue;
if (j>i||w>i)
{
continue;
}
dp[i][j][w]=0;
dp[i][j][w]=(dp[i][j][w]+1ll*dp[i-1][j][w]*(j*w-(i-1)))%k;
dp[i][j][w]=(dp[i][j][w]+1ll*dp[i-1][j-1][w]*(n-j+1)*w)%k;
dp[i][j][w]=(dp[i][j][w]+1ll*dp[i-1][j][w-1]*(m-w+1)*j)%k;
}
}
}
printf("%d\n",dp[n*m][n][m]%k);
}
}