博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Gym 101194H 2016 ecfinal H题
阅读量:7103 次
发布时间:2019-06-28

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

题意

  给一个\(n*m\) 的格子矩阵,现在要在这些格子里面填数,填的数字是 \([1,k]\) 中的整数,每个数可以填多次。定义好格子:一个格子所在的行和列中的每个格子中的数都严格小于该格子中的数。假设 \(A_g\) 为矩阵中好格子数量为 \(g\) 时填数的方案数,现在要输出 \(\sum_{g=0}^{n*m}(g+1)A_g\)

分析

首先我们将输入出的表达式拆分开得到 \(\sum_{g=0}^{n*m}gA_g+\sum_{g=0}^{n*m}A_g\) ,回顾一下 \(A_g\) 表示的是矩阵中有 \(g\) 个好格子的方案数。然后我们先看两个加数后面的那个部分表示的含义,直观上看这个和包括不存在好格子时的方案数;只有一个好格子时的方案数;有 \(n*m\) 个好格子时的方案数等。这样的话无论怎么填数,其结果都是上述情况中的一种。那么很显然这一部分的方案数应该是 \(K^{n*m}\). 下面我们再看看前面这一部分,跟后面不一样的是这里所求的和的每一项都带了一个系数 \(g\) 表示有 \(g\) 个好格子时的方案数应该乘以该系数。这样我们不好直接找通项求和,那么我们现在换个思路求。我们将重心放到 \(n*m\) 个格子上,而不是原来的 \(g\) 上。意思就是我们看当第 \(x\) 行,第 \(y\) 列的这个格子是好格子的时候,他能填数的方案数时多少,再看看他对整个结果的贡献是多少。两者相乘,就可以作为答案的一部分。这里强调一下,因为看的是每个格子的贡献,所以只要贡献算对了是不会有重复的。下面这块有一个转化,举个例子说明。当只有一个格子是好格子的时候,按原来整体的思想答案应该是 \(A_1\) 假设格子1 \((x_1,y_1)\) 和格子2 \((x_2,y_2)\) 有且仅有这两块格子是好格子,很显然他们不可能在同一行或者同一列。那么当我们用原来的整体思想来看的话应该,此时的答案应该是 \(2*A_2\) 这时候我们可以将这两份 \(A_2\) 同时分给 格子1和格子2。再看如果只有三个好格子的情况,同样的原来的答案是 \(3*A_3\), 我们可以把这三个分给那三个好格子。以此类推,那这样我们发现,对于每个格子 \((x,y)\) 他的贡献应当是 \(\sum^{m*n}_{i=1}A_g\) 。这样我们我们会发现,如果 \(i\) 从0开始那么就是随便乱摆,但是这里是从1开始的,那么我们应当保证至少有一个格子是好格子,其他的就可以随便乱摆了,分析和上面 \(i\) 从0开始是一样的,这里就不细说了。现在我们来看好格子和与之同行同列的格子填数的种类,首先好格子必至少填2,其他的全填1;好格子的填数范围是 \([1,k]\) ,其他的只要比这个数小就行了,一共有 \(m-1+n-1\) 个数,每个数可以是 \([1,i-1]\)(\(i\)是好格子的填的数)一共 \(i-1\)个数 。那么这一块的种类数就是 \(\sum_{i=2}^{k}(i-1)^{m-1+n-1}\)。然后剩下的数就是随便乱填了,剩余 \((n-1)*(m-1)\) 个数,每个数可以填 \([1,k]\),所以是 \(k^{(n-1)*(m-1)}\) 种。最后我们只考虑了一个地方的好格子,一共有 \(m*n\)个地方,所以还要乘以 \(m*n\)。综上,最后的答案就是这个

\[n*m\sum_{i=2}^{k}(i-1)^{n-1+m-1}k^{(n-1)*(m-1)}\]

代码

#include 
using namespace std;typedef long long ll;const ll mod = 1e9 + 7;ll pow_m(ll a, ll b){ ll res = 1; while (b) { if (b & 1) res = res * a%mod; a = a * a%mod; b >>= 1; } return res;}int main(){ int t, ca = 1; scanf("%d", &t); while (t--) { ll n, m, k; scanf("%lld%lld%lld", &n, &m, &k); ll ans = 0; for (int i = 2; i <= k; i++) ans = (ans + pow_m(i - 1, n + m - 2)) % mod; ans = ans * n*m%mod;; ans = ans * pow_m(k, (n - 1)*(m - 1)) % mod; ans = (ans + pow_m(k, m*n)) % mod; printf("Case #%d: %lld\n",ca++, ans); } return 0;}

转载于:https://www.cnblogs.com/destimind/p/10304941.html

你可能感兴趣的文章
JAVA多线程之volatile 与 synchronized 的比较
查看>>
一个经典编程面试题的“隐退”
查看>>
POJ2109
查看>>
显示创建一个表的SQL语句
查看>>
光流和KLT
查看>>
Linux c括号作用域【原创笔记】
查看>>
分分钟带你玩转 Web Services【2】CXF
查看>>
ASP.NET MVC+LINQ开发一个图书销售站点(7):图书分类管理
查看>>
如何做一名技术管理者
查看>>
Resouce, platform_device 和 platform_driver 的关系【转】
查看>>
HTML标记大全参考手册(转载)
查看>>
查看表空间与对应的表空间文件
查看>>
linux C判断文件是否存在【转】
查看>>
《J2EE Tutorial中文版》读书笔记(1)
查看>>
Solaris关机重启命令小结
查看>>
如何为编程爱好者设计一款好玩的智能硬件(四)——初尝试·把温湿度给收集了(上)!...
查看>>
HTTP POST GET 本质区别详解
查看>>
PHP使用Simple_HTML_DOM遍历、过滤及保留指定属性
查看>>
MongoDB学习笔记~Mongo集群和副本集
查看>>
12个有趣的C语言问答
查看>>