题目链接:hdu 6415 Rikka with Nash Equilibrium
Sample Input
2
3 3 100
5 5 2333
Sample Output
64
1170
题意: n*m的矩阵,填入1~n*m的数字,若某个数字是这个数字所在行列的最大值,那么这个数字就被称为Nash Equilibrium,现在要求你构造的矩阵只存在一个Nash Equilibrium数,输出构造方案数,并取模K。
思路:dp[i][j][k]代表,已经放入了i个数字,占了j行k列。我们从大到小放入数字,下图中横线代表放过数字的行,竖线表示方过数字的列。现在我们放入一个新的数字,这个数字肯定比已经放好的数字小(因为我们是从大到小放的),只要这个数字放入位置的行或者列至少有一个已经有数字了,那么这个数字肯定不会是Nash Equilibrium数,是符合条件的。所以我们有三种转移的情况:
1.放入的数字新增加了一行:dp[i+1][j+1][k],看下图的红×位置,有m*(n-j)个位置
2.放入的数字新增加了一列:dp[i+1[j][k+1],看下图的红圈位置,有n*(m-k)个位置
3.放入的数字不增加行列:dp[i+1][j][k],看下图的绿圈位置,有j*k-i个位置
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
ll dp[6403][81][81];//不能开太大,不然会T
int main(){
int t;
scanf("%d",&t);
while(t--){
int n,m;
ll mod;
scanf("%d%d%lld",&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++){
if(max(j,k)>i)break;
if(!dp[i][j][k])continue;
if(j<n) dp[i+1][j+1][k]=(dp[i+1][j+1][k]+dp[i][j][k]*(n-j)%mod*k%mod+mod)%mod;
if(k<m) dp[i+1][j][k+1]=(dp[i+1][j][k+1]+dp[i][j][k]*j%mod*(m-k)%mod+mod)%mod;
if(i<j*k) dp[i+1][j][k]=(dp[i+1][j][k]+dp[i][j][k]*(k*j-i)+mod)%mod;
}
}
}
printf("%lld\n",dp[n*m][n][m]%mod);
}
return 0;
}