HDU6052-To my boyfriend

216 篇文章 0 订阅

To my boyfriend

                                                                Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
                                                                                          Total Submission(s): 977    Accepted Submission(s): 452


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
 

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).
 

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.666666667
Hint
6(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)
 

Source
 


题意:给出一个n*m的矩阵,每个点有一种颜色,定义矩阵的val为矩阵中不同颜色的数量,问任意一个子矩阵的val的期望为多少

解题思路:期望=所有子矩阵的val总和/子矩阵个数。子矩阵个数很明显为n*(n+1)*m*(m+1)/4。然后就是求所有子矩阵val的总和。在考虑颜色i的时候,把颜色i的点看作关键点,求出至少包含一个关键点的子矩阵个数。先排个序(行号升序,列号升序)。把每个合法的矩阵算在序最小的那个关键点头上,这样就可以保证不重复,不遗漏。在找包含第一个关键点的矩阵的时候,显然没有任何限制,只需要包含这个点就行了。找第二个关键点的矩阵的时候,不能包含第一个点……找第i个关键点决定的矩阵的时候,不能包含1..i-1这i-1个点,每次求一个点的答案的时候维护好边界即可



#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <functional>

using namespace std;

#define LL long long
const int INF = 0x3f3f3f3f;
const LL mod = 1000000007;

int n, m;
vector<pair<int, int> > g[10010];
vector<int> a[110];
int x;

LL solve(int k)
{
    LL ans = 0;
    for (int i = 1; i <= n; i++) a[i].clear();
    int Size = g[k].size();
    for (int i = 0; i < Size; i++)
    {
        int x = g[k][i].first, y = g[k][i].second;
        int l = 1, r = m;
        bool flag = 0;
        for (int i = x; i >= 1; i--)
        {
            int Size1 = a[i].size();
            for (int j = 0; j < Size1; j++)
            {
                int k = a[i][j];
                if (k < y) l = max(l, k + 1);
                else if (k > y) r = min(r, k - 1);
                else { flag = 1; break; }
            }
            if (flag) break;
            ans += 1LL * (n - x + 1) * (y - l + 1) * (r - y + 1);
        }
        a[x].push_back(y);
    }
    return ans;
}

int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d %d", &n, &m);
        for (int i = 0; i <= n * m; i++) g[i].clear();
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++) scanf("%d", &x), g[x].push_back(make_pair(i, j));
        LL ans = 0;
        for (int i = 0; i <= n * m; i++)
            ans += solve(i);
        printf("%.9lf\n", 1.0*ans / ((n + 1)*n*m*(m + 1) / 4));
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值