2018 Multi-University Training Contest 9 1001 Rikka with Nash Equilibrium(hdu 6415)(dp)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yz467796454/article/details/81904171

题目链接: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;
}

猜你喜欢

转载自blog.csdn.net/yz467796454/article/details/81904171