您的位置:首页 > 其它

hdu 6052 To my boyfriend

2017-08-09 19:28 423 查看


题意

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

 


思路

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

于是我们考虑每种数字对结果的贡献,计算至少包含某一数字的子矩阵有多少个,但因为如此一定会产生重复计数,所以我们要为其限定条件。
假设相对的两点 (x1,y1),(x2,y2)(x1,y1),(x2,y2) 可以唯一确定一个矩形,且 x1<=x2,y1<=y2x1<=x2,y1<=y2
对于当前所判断的数字 aa ,其坐标为 (x,y)(x,y)
此时, (x1,y1)(x1,y1) 的位置只可以在 (x,y)(x,y) 的左上方, (x2,y2)(x2,y2) 的位置只可以在 (x,y)(x,y) 的右下方(包含当前行)
且最终 (x,y)(x,y) 以上以左部分无第二个数字 aa

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

接下来的工作便是找寻当前位置 (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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: