Rikka with Nash Equilibrium
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 507 Accepted Submission(s): 210
Problem Description
Nash Equilibrium is an important concept in game theory.
Rikka and Yuta are playing a simple matrix game. At the beginning of the game, Rikka shows an n×m integer matrix A. And then Yuta needs to choose an integer in [1,n], Rikka needs to choose an integer in [1,m]. Let i be Yuta's number and j be Rikka's number, the final score of the game is Ai,j.
In the remaining part of this statement, we use (i,j) to denote the strategy of Yuta and Rikka.
If the strategy is (1,2), the score will be 2; if the strategy is (2,2), the score will be 4.
A pure strategy Nash equilibrium of this game is a strategy (x,y) which satisfies neither Rikka nor Yuta can make the score higher by changing his(her) strategy unilaterally. Formally, (x,y) is a Nash equilibrium if and only if:
{Ax,y≥Ai,y ∀i∈[1,n]Ax,y≥Ax,j ∀j∈[1,m]}
In the previous example, there are two pure strategy Nash equilibriums: (3,1) and (2,2).
To make the game more interesting, Rikka wants to construct a matrix A for this game which satisfies the following conditions:
1. Each integer in [1,nm] occurs exactly once in A.
2. The game has at most one pure strategy Nash equilibriums.
Now, Rikka wants you to count the number of matrixes with size n×m which satisfy the conditions.
Input
The first line contains a single integer t(1≤t≤20), the number of the testcases.
The first line of each testcase contains three numbers n,m and K(1≤n,m≤80,1≤K≤109).
The input guarantees that there are at most 3 testcases with max(n,m)>50.
Output
For each testcase, output a single line with a single number: the answer modulo K.
Sample Input
2 3 3 100
5 5 2333
Sample Output
64 1170
题意:
对于一个n*m的矩阵,如果某个位置上的数满足即是行最大值,也是列最大值,那么这个位置被称为纳什均衡点,问有多少个矩阵,满足①n行m列;②矩阵中的所有数都是1~n*m中的其中一个,且独一无二;③矩阵中最多只有一个纳什均衡点,答案对K取模
思路:
- 因为条件②,所以最大的那个数(n*m)所在位置一定是纳什均衡点
- 考虑从最大的数字开始填,n*m可以填在任意一个位置,总共n*m种填法
- 第二个数n*m-1很显然只能和最大数同一行或者同一列,共有n+m-1种情况
- 同理, 前两个数如果在同一行,第三个数n*m-2可以填在其中两列或者一行,共有2*n+m-2中情况,前两个数如果在同一列,第三个数n*m-2可以填在其中两行或者一列,共有n+2*m-2种情况
- ……
考虑dp[x][y][z]表示当前填到数字z,z只能填入其中x行y列中,如下图
状态为dp[3][4][93],意思就是当前要填数字93,只能填在前4列,前3行
- 如果填在左上角(左上角还有5个位置),那么有转移:dp[3][4][93] += 5*dp[3][4][92];
- 如果填在右上角,那么有转移:dp[3][4][93] += (m-4)*3*dp[3][5][92]
- 如果填在左下角,那么有转移:dp[3][4][93] += 4*(n-3)*dp[4][4][92]
- 不能填在右下角
总体复杂度O(n²m²)
#pragma comment(linker, "/STACK:102400000,102400000")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
#include<math.h>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
#define LL long long
LL n, m, mod, dp[82][82][6450], jc[6450] = {1};
LL Sech(LL x, LL y, LL p)
{
LL ans, now;
if(x==n || y==m)
return jc[p];
if(dp[x][y][p]!=-1)
return dp[x][y][p];
ans = 0;
now = x*y-(n*m-p);
if(now>=1)
ans = (ans+Sech(x, y, p-1)*now)%mod;
ans = (ans+(n-x)*y*Sech(x+1, y, p-1))%mod;
ans = (ans+(m-y)*x*Sech(x, y+1, p-1))%mod;
dp[x][y][p] = ans;
return ans;
}
int main(void)
{
LL T, i;
scanf("%lld", &T);
while(T--)
{
scanf("%lld%lld%lld", &n, &m, &mod);
for(i=1;i<=6446;i++)
jc[i] = jc[i-1]*i%mod;
memset(dp, -1, sizeof(dp));
printf("%lld\n", n*m*Sech(1, 1, n*m-1)%mod);
}
}