【杂题总汇】HDU2018多校赛第九场 Rikka with Nash Equilibrium

【HDU2018多校赛第九场】Rikka with Nash Equilibrium

又是靠这样一道题擦边恰好和第两百名分数一样~愉快🙃

+HDU传送门+


 

◇ 题目

<简要翻译>

构造一个r*c的矩阵,矩阵内的元素为 1~r*c ,且每个元素只出现一次(即矩阵的元素是1~r*c的一个排列)。

定义一种特殊数 x 当且仅当在矩阵中 x 同时是其所在行的最大值和所在列的最大值。例如:

现要求构造出的矩阵中恰好有一个特殊数,求能够构造出多少个不同矩阵,将所得答案模mod。

<输入&输出>

第一行一个整数T,表示数据的组数。每组数据包含一行——3个整数r,c,mod。每行输出一个整数,表示每组数据的答案。

<样例&解析>

Input Output Explain

2

3 3 100

5 5 2333

64

1170

对于第一组数据,一组解为:

| 3  9  2 |

| 6  4  5 |

| 7  8  1 |

其中特殊数为9.

 

 

 

 

 

 

 


 

◇ 解析

因为每个元素在矩阵中只出现一次,且最大元素是 r*c ,所以 r*c 的元素一定是一个特殊数(矩阵中没有比它大的数,所以行和列中也没有)。所以除了 r*c 以外没有其他的特殊数。

考虑该矩阵的构造方式,把元素1~r*c从大到小放入矩阵中。第一个元素可以放在任意一个位置,则有 r*c 种方案。设现在正在放第i个(非第一个)元素,为了防止当前元素成为特殊数,则应该放在之前放置的元素所在的行或列,因为如果不这样放置,之后放置的元素都将比第i个元素小,所以元素i所在行和列都不存在比它大的元素,也就成了特殊数,不满足条件。若按照该规则放置,则有三种情况:

① 第i个元素的所在列有之前放置的元素,但行没有;

② 第i个元素的所在行有之前放置的元素,但列没有;

③ 第i个元素的所在行和列都有之前放置的元素。

我们可以发现第一个元素放在任意位置,能够形成的方案数都是相同的。所以我们可以通过DP来解决这道题!

这道题影响答案的只有 “当前放置的元素”k,“已经放置有元素的行数”i,“已经放置有元素的列数”j。则dp[i][j][k]表示放置k后已经有i行、j列放置了元素。很容易发现,从小到大放元素和从大到小是等价的!所以这里我从1开始放置,元素1可以放置在矩阵的任意位置,共 r*c 种方案,即 dp[1][1][1] 初值为 1(元素1放置后有一行、一列已经放置有元素)。对于上述的三种情况写出转移式:

① 第i个元素放置在已经有元素的列上,但行上没有其他元素,则行数增加1,从 dp[i-1][j][k-1] 转移,由于有j列已经放置元素,且有 [r-(i-1)] 行没有放置元素,则共 j*(r-i+1) 个位置可以放;

② 第i个元素放置在已经有元素的行上,但列上没有元素,与情况①恰好相反,共有 i*(c-j+1) 个位置;

③ 第i个元素放置的行和列上都有元素,则行列都不增加,即 dp[i][j][k-1] ,总共有 i*j 个位置是行和列上都有元素,但已经放置了(k-1)个元素在这些位置(因为在某位置放置一个元素后,该位置必然行和列都有元素,即放置的那个元素),所以剩余可以放的位置为 (i*j-k+1),此时需要保证 (i*j-k+1)为正数。

总结一下,得到状态转移方程式为:

还是比较简洁,三重循环分别从大到小枚举 i,j,k 就可以了。注意开 long long ,处处取模!(最大为1e9,1e9*1e9时因为还没有模mod,会炸掉……)

最后输出答案就是dp[r][c][r*c],即每行都有元素,且已经放置了第r*c个元素。

 


 

◇ 源代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int r,c;
long long mod;
long long dp[85][85][6405];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%lld",&r,&c,&mod);
        memset(dp,0,sizeof dp);
        dp[1][1][1]=1ll*r*c;
        for(int i=1;i<=r;i++)
            for(int j=(i==1?2:1);j<=c;j++)
                for(int k=1;k<=i*j;k++)
                {
                    int A=0,B=0,C=0;
                    A=dp[i-1][j][k-1]*j*(r-i+1)%mod;
                    B=dp[i][j-1][k-1]*i*(c-j+1)%mod;
                    if(i*j-k+1>=0) 
                        C=dp[i][j][k-1]*(i*j-k+1)%mod;
                    dp[i][j][k]=((A+B)%mod+C)%mod;
                }
        printf("%lld\n",dp[r][c][r*c]%mod);
    }
}

  


 

The End

Thanks for reading!

- Lucky_Glass

(Tab:如果我有没讲清楚的地方可以直接在邮箱lucky_glass@foxmail.com email我,在周末我会尽量解答并完善博客~📃)
posted @ 2018-08-20 19:15  Lucky_Glass  阅读(328)  评论(0编辑  收藏  举报
TOP BOTTOM