HDU 6052 暴力计数

题意:

题目链接: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 
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;
}

你可能感兴趣的:(暴力,容斥原理)