博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【杂题总汇】HDU2018多校赛第九场 Rikka with Nash Equilibrium
阅读量:7080 次
发布时间:2019-06-28

本文共 2448 字,大约阅读时间需要 8 分钟。

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

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


 

◇ 题目

<简要翻译>

构造一个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
#include
#include
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我,在周末我会尽量解答并完善博客~?)

转载于:https://www.cnblogs.com/LuckyGlass-blog/p/9507466.html

你可能感兴趣的文章
Python爬虫之使用MongoDB存储数据
查看>>
python奇遇记:深入理解装饰器
查看>>
web-push实现原理及细节介绍
查看>>
MongoDB 分片配置
查看>>
elasticsearch概念详解
查看>>
matplotlib Basic Usage
查看>>
高性能磁盘 I/O 开发学习笔记 -- 软件手段篇
查看>>
ueditor中的问题记录
查看>>
基于后端云微信小程序开发
查看>>
Python pyspider 安装与开发
查看>>
hexo+css创建自己的blog(搭建)
查看>>
[译] 使用 Sami 生成 PHP 文档
查看>>
GitChat · Python | 零基础小白如何入门 Python 编程
查看>>
Spring、Spring Boot和TestNG测试指南 - 测试Spring MVC
查看>>
Memory Management and Circular References in Python
查看>>
用node+express+mongoDB实现用户登录注册模板
查看>>
微信小程序server-2-实现会话层
查看>>
vim下处理文档中的\r\n\t字符
查看>>
php常见术语
查看>>
看例子,学 Python(三)
查看>>