Problem Description
Dear Liao
I never forget the moment I met with you. You carefully asked me: "I have a very difficult problem. Can you teach me?". I replied with a smile, "of course". You replied:"Given a matrix, I randomly choose a sub-matrix, what is the expectation of the number of **different numbers** it contains?"
Sincerely yours,
Guo
I never forget the moment I met with you. You carefully asked me: "I have a very difficult problem. Can you teach me?". I replied with a smile, "of course". You replied:"Given a matrix, I randomly choose a sub-matrix, what is the expectation of the number of **different numbers** it contains?"
Sincerely yours,
Guo
Input
The first line of input contains an integer T(T≤8) indicating the number of test cases.
Each case contains two integers, n and m (1≤n, m≤100), the number of rows and the number of columns in the grid, respectively.
The next n lines each contain m integers. In particular, the j-th integer in the i-th of these rows contains g_i,j (0≤ g_i,j < n*m).
Each case contains two integers, n and m (1≤n, m≤100), the number of rows and the number of columns in the grid, respectively.
The next n lines each contain m integers. In particular, the j-th integer in the i-th of these rows contains g_i,j (0≤ g_i,j < n*m).
Output
Each case outputs a number that holds 9 decimal places.
Sample Input
1 2 3 1 2 1 2 1 2
Sample Output
1.666666667Hint6(size = 1) + 14(size = 2) + 4(size = 3) + 4(size = 4) + 2(size = 6) = 30 / 18 = 6(size = 1) + 7(size = 2) + 2(size = 3) + 2(size = 4) + 1(size = 6)题意:给出一个n*m(1<=n,m<=100)的矩阵,每个矩阵元素有一个颜色值ai(0<=ai<=10000),现在定义一个子矩阵的value为子矩阵中不同颜色的数量,求子矩阵value的期望。思路:数学期望=所有矩阵value数值之和/矩阵的个数首先解决矩阵的个数问题,直接枚举(i,j)以(i、j)为右下角的矩阵个数为i*j个,这样就能得到所有矩阵的个数然后需要解决的是所有矩阵的value值,直接暴力找每个矩阵中不同颜色的数量肯定是不行的,所以我们可以换个思路,我们可以枚举每个位置,然后计算一下该位置上的颜色对结果的贡献,但是由于每个位置的颜色不是独一无二的,有的位置的颜色是一样的,这样的话我们需要采用容斥原理去重,但是这个题目中只要按照一定的规则枚举就能避免重复的情况,我们选择从下到上,从左到右的规则枚举,当我们枚举到某个位置时,我们需要确定这个位置的颜色所在矩阵的上边界和左右边界 (以枚举的位置为其下边界),具体确定方法看代码注释ac代码:#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)//如果上限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);//(下边界方案*左边界方案*右边界方案,上边界已经确定是xi) } return res; } int main() { 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; }