HDU6415(DP)

14 篇文章 0 订阅

题意

给两个整数n,m,让你构造一个矩阵n*m的矩阵,此矩阵满足一下两点:

1.只有一个元素在它的此行和此列中都是最大的(纳什均衡点)。

2.矩阵中1~n*m中的数都恰好出现一次。

问有多少种构造方法?

 题解

从大到小的放,下一个数需要放在已经被放过数的的行和列上,不然这个点就会成为新的纳什均衡点。

我们设dp(i,j,k)表示当前已经放了i个数且有j行k列被放过数了。那么就有三种状态转移。

1.下一个数可以放在新的一行dp[i+1][j+1][k] += k*(n-j)*dp[i][j][k](第i+1个数放的方法有k*(n-j)种)

2.下一个数可以放在新的一列dp[i+1][j][k+1] += j*(m-k)*dp[i][j][k](第i+1个数放的方法有j*(m-k)种)

3.下一个数放在了已有行列的交点上dp[i+1][j][k] += (j*k-i)*dp[i][j][k](第i+1个数放的方法有(j*k-i)种)

 代码

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <math.h>
#include <map>
#include <vector>
#include <string.h>
using namespace std;
const int maxn = 82;
typedef long long ll;
int mod;
ll dp[2][maxn][maxn];
int n, m;
int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d%d", &n, &m, &mod);
        memset(dp, 0, sizeof(dp));
        dp[0][1][1] = n*m;
        int ne, now = 0;
        for(int i = 2; i <= n*m; i++)
        {
            ne = now^1;
            memset(dp[ne], 0, sizeof(dp[ne]));
            for(int j = 1; j <= n; j++)
            {
                for(int k = 1; k <= m; k++)
                {
                    if(dp[now][j][k]) {
                        dp[ne][j+1][k] = (dp[ne][j+1][k]+dp[now][j][k]*(n-j)*k)%mod;

                        dp[ne][j][k+1] = (dp[ne][j][k+1]+dp[now][j][k]*(m-k)*j)%mod;
                        ll p=j*k-i+1;
                        dp[ne][j][k]=dp[ne][j][k]+p*dp[now][j][k]%mod;
                    }

                }
            }
            now = ne;
        }
        printf("%I64d\n",dp[now][n][m]%mod);

    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值