题意:
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6052
对于一个n*m的方格,每个格子中都包含一种颜色,求出任意一个矩形包含不同颜色的期望。
思路:
算贡献,计数问题,这种可能会重复的计数,为了避免重复,需要规定一个计算的顺序,比如按照从上到下,从左到右的顺序给每个同色的点排个序,计算这个颜色的贡献时,对于第i个点,可以计算包括点i以及包括之后所有同色点的矩形数目,但是不能计算包括i之前的点的矩形数目,这样就可以不重复的计算。如果按照从上到下,从左到右的顺序计算,那么对于当前点x,和它同色且在他上方和左边的点都不能包括。
这样问题就转化为,对于每个点,我们要求在当前限制点的条件下,能覆盖这个点,但不能覆盖限制点的最大矩形的上下左右边界。
首先枚举上边界,同时维护左右边界的值,对于每个枚举的上边界,更新左右边界的值,然后计算在固定上边界的情况下,有多少个矩形可以覆盖x点(i,j),若此时左右边界分别是L,R,那么包括x的点的矩形数目为(j-L+1)(R-j+1)(n-i+1)。
更新左右边界的过程,可以优化,但事实上暴力就能过了。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 105;
int n, m;
int color[MAXN][MAXN];
int cal(int x, int y) {
LL res = 0;
int c = color[x][y], L = 1, R = m;
for (int i = x; i >= 1; i--) {
if (i < x && color[i][y] == c) break;
int l = y, r = y;
for (int j = y - 1; j >= max(1, L); j--) {
if (color[i][j] == c) break;
l = j;
}
L = max(L, l);
if (i == x) {
res += (LL)(n - x + 1LL) * (y - L + 1LL) * (R - y + 1LL);
continue;
}
for (int j = y + 1; j <= min(m, R); j++) {
if (color[i][j] == c) break;
r = j;
}
R = min(R, r);
res += (LL)(n - x + 1LL) * (y - L + 1LL) * (R - y + 1LL);
}
//printf("(%d, %d) %I64d\n", x, y, res);
return res;
}
int main() {
//freopen("in.txt", "r", stdin);
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++)
scanf("%d", &color[i][j]);
}
LL gg = 0, ss = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
gg += cal(i, j);
ss += i * j;
}
}
printf("%.9f\n", gg * 1.0 / ss);
}
return 0;
}