矩阵颜色
Problem
一个
Input
第一行两个正整数
接下来
Output
输出子矩阵的平均颜色数,保留
Sample
Input 1
2 3
1 2 1
2 1 2
Output 1
1.666666667
Solution
容易发现,颜色之间互不影响,可以分开考虑每种颜色对答案的贡献。
如下图所示,涂色的格子表示同一颜色,我们将其按照遍历的顺序编号。
为了避免重复计算,我们规定在统计包含编号为
这些障碍规定了矩阵的左右区间范围,且满足单调性,第
由于矩阵要包含目标格子,坐标记为
如下图,计算以第
当扫到第
当上界为第
当上界为第
那么确定了左右范围,如何统计贡献呢?
先看看一维的情况。
如图,我们要选一个包含
回到矩阵上,一维情况求的是矩阵的长的取值。宽的上界由枚举确定,下界取值在
因此,合法的矩阵总共有
最后,统计完一个格子的贡献后,要更新该格子对这种颜色的左右区间范围的限制。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iomanip>
using namespace std;
const int kmax = 105;
int n, m, c[kmax][kmax];
int p[kmax][kmax * kmax];
int l[kmax], r[kmax];
long long res, resc;
void Calc(int x, int y, int c) {
for (int i = 1; i <= n + 1; i++) {
l[i] = 0, r[i] = m + 1; // 初始化左右区间
}
for (int i = 1; i < y; i++) {
l[p[i][c]] = max(l[p[i][c]], i); // 计算左区间
}
for (int i = y + 1; i <= m; i++) {
r[p[i][c]] = min(r[p[i][c]], i); // 计算右区间
}
for (int i = x; i > p[y][c]; i--) {
l[i] = max(l[i], l[i + 1]), r[i] = min(r[i], r[i + 1]); // 边计算边更新
// cout << i << ' ' << l[i] << ' ' << r[i] << '\n';
res += 1ll * (n - x + 1) * (y - l[i]) * (r[i] - y);
}
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> c[i][j];
}
}
resc = n * (n + 1) / 2 * m * (m + 1) / 2; // 总的矩阵数量
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
Calc(i, j, c[i][j]); // 计算贡献
p[j][c[i][j]] = i; // 更新限制
}
}
// cout << res << '\n';
cout << fixed << setprecision(9) << 1.0 * res / resc << '\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效