dp是不可能的,这辈子都写不出的。。。
当放最大数字的时候只能占据一行一列
其余的数字
1. 只占据1行
2. 只占据1列
3. 填充在被占据过的行和列里面
这里需要对取模优化
有两种方法吧
1. 减少取模次数
2. 结果值改成int,每次都存到int里面
void update(int &k1,long long k2){//后面的数字用来存储可能爆int的乘法
k1=(k1+k2)%mo;
}
增加新的点不增加行列:放在交点
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll dp[6455][85][85]; //dp[i][j][k]:有i个点,占据了j行k列有几种放法
int main()
{
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=1;i<n*m;i++)
{
for(int j=1;j<=n;j++)
{
for(int k=1;k<=m;k++)
{
dp[i+1][j+1][k]=(dp[i+1][j+1][k]+(n-j)*k*dp[i][j][k])%mod; //占据的新的一行所能放的可能
dp[i+1][j][k+1]=(dp[i+1][j][k+1]+(m-k)*j*dp[i][j][k])%mod; //占据的新的一列所能放的可能
if(dp[i+1][j+1][k]>=mod) dp[i+1][j+1][k]%=mod; //mod太多会超时,微弱优化
if(dp[i+1][j][k+1]>=mod) dp[i+1][j+1][k]%=mod;
ll p=j*k-i; //计算有多少个可以放的交点
if(p<=0) continue; //不能放就跳过
dp[i+1][j][k]=dp[i+1][j][k]+p*dp[i][j][k]; //放交点不增加行列
if(dp[i+1][j][k]>=mod) dp[i+1][j][k]%=mod;
}
}
}
printf("%lld\n",dp[n*m][n][m]%mod);
}
return 0;
}