hdu 6052 To my boyfriend



题意

给出一个  N×M N×M 的数字矩阵,求其所有子矩阵不同数字个数的期望值。

 

思路

直接枚举子矩阵的时间复杂度为  O(n4) O(n4) ,显然不能达到预期的效果。

于是我们考虑每种数字对结果的贡献,计算至少包含某一数字的子矩阵有多少个,但因为如此一定会产生重复计数,所以我们要为其限定条件。

  • 假设相对的两点  (x1,y1),(x2,y2) (x1,y1),(x2,y2) 可以唯一确定一个矩形,且  x1<=x2,y1<=y2 x1<=x2,y1<=y2
  • 对于当前所判断的数字  a a ,其坐标为  (x,y) (x,y)
  • 此时,  (x1,y1) (x1,y1) 的位置只可以在  (x,y) (x,y) 的左上方,  (x2,y2) (x2,y2) 的位置只可以在  (x,y) (x,y) 的右下方(包含当前行)
  • 且最终  (x,y) (x,y) 以上以左部分无第二个数字  a a

这样便不会产生重复计数啦~

接下来的工作便是找寻当前位置  (x,y) (x,y) 以上以左的空间中存在多少个可选择点,然后配合其以下以右的空间大小得出结果。

 在求整个矩阵的子矩阵总数时,我们可以将其看作分别求出包含各点的子矩阵数,但由于所有子矩阵的边界都相等,所以只固定一个边界会重复计算很多个,所以我们需要固定两个相邻的边界,让每个子矩阵都是这两个边界固定来保证不重复计算,所以我们可以直接将下边界和右边界固定,此时的包含格子 (x,y)的子矩阵数为 (y-l+1)*(x-u+1) ,由于我们的数组下标都是从0开始,所以 l=0,u=0 ,相当于 (y+1)*(x+1) ,既然这样,我们不如直接让下标从1开始往后存,也就是 x*y ,这样的话,总子矩阵数就是各个格子坐标乘积的总和 


#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn=105;
int color[maxn*maxn][maxn];
int l[maxn],r[maxn];
ll ans=0;
int n,m;
void solve(int x,int y,int c)
{
    for(int i=1;i<=x;i++)
    {
        l[i]=0;r[i]=m+1;
    }
    for(int i=1;i<y;i++)
        l[color[c][i]]=i;
        for(int i=m;i>y;i--)
        r[color[c][i]]=i;
    int h=color[c][y];
    for(int i=x-1;i>h;i--)
    {
        l[i]=max(l[i],l[i+1]);
        r[i]=min(r[i],r[i+1]);
    }
    for(int i=x;i>h;i--)
    {
        ans+=ll(n-x+1)*(r[i]-y)*(y-l[i]);
    }
}
int main (){
  int t;
  scanf("%d",&t);
  while(t--)
  {
      scanf("%d%d",&n,&m);
      memset(color,0,sizeof(color));
      ans=0;
      for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
      {
          int x;
          scanf("%d",&x);
          solve(i,j,x);
          color[x][j]=i;
      }
      ll tem=n*(n+1)*m*(m+1)/4;
      printf("%.9lf\n",ans*1.0/tem);
  }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值