题目链接:HDU - 6415
我们假设是从大到小放,那么我们可以发现当前放的时候,必须在已经放过的一行或者一列放。
那么就成了一个dp问题了,dp[i][j][k]前 i 个数字,已经放了 j 行,k 列的方案数。
因为每个数只和之和前一个数字有关,所以可以空间优化。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=85;
int n,m,mod,dp[2][N][N],now;
inline void add(int &x,int y){x+=y; if(x>=mod) x-=mod;}
inline void solve(){
cin>>n>>m>>mod; memset(dp,0,sizeof dp); now=0;// dp[0][0][0]=1%mod;
dp[0][1][1]=n*m%mod;
for(int i=2;i<=n*m;i++){
now^=1; memset(dp[now],0,sizeof dp[now]);
for(int j=1;j<=n;j++){
for(int k=1;k<=m;k++) if(j*k>=i){
add(dp[now][j][k],1LL*dp[now^1][j][k]*(j*k-i+1)%mod);
add(dp[now][j][k],1LL*dp[now^1][j-1][k]*(n+1-j)%mod*k%mod);
add(dp[now][j][k],1LL*dp[now^1][j][k-1]*(m+1-k)%mod*j%mod);
}
}
}
printf("%d\n",dp[now][n][m]);
}
signed main(){
int T; cin>>T; while(T--) solve();
return 0;
}