2017第二次多校联合 hdu6052 tobemyboyfriend

来源:互联网 发布:淘宝宝贝排名不稳定 编辑:程序博客网 时间:2024/05/22 17:28

假装这里有链接

题意:给你一个矩阵,每个格子有种颜色,求任意大小子矩阵的期望。

解:期望=所有子矩阵颜色数和/子矩阵个数。那首先要解决的就是子矩阵个数,如果已知矩阵右下角(i,j),那左边界和上边界一定在(0,0)~(i,j)里,就是i*j。
然后解决所有子矩阵颜色数和,可以求每个颜色包含在多少矩阵里,因为可能会重复,所以自上而下,自左而右考虑。便利每个点,假设便利到(x,y),便利x的左边界(因为自左而右考虑,所以x的右边是不会重复的),x的右边界这时候就是m,左边界就是和x同行的与x的颜色相同的位置,然后便利(x-1)行,寻找左边界右边界,但是要考虑x行的边界,
所以(x-1)行的左边界是x行的左边界,同理(x-1)行的右边界是x行的右边界的。然后如果便利到了这一行的左右边界LR,那么满足条件的矩阵就是(y-L+1)(R-y+1)(n-x+1)个。
要注意如果x上面恰好有一个已经便利过的与x同色的点S的话,S这一行是不能便利的,这时就结束便利,计算所有矩阵。

#include<bits/stdc++.h>using namespace std;#define ll long longconst int maxn=105;int co[maxn][maxn];int n,m;int solve(int x,int y){    ll sum=0;    int c=co[x][y];    int L=1,R=m;    for(int i=x;i>=1;i--)    {        if(i<x&&co[i][y]==c)break;        for(int j=y-1;j>=max(L,1);j--)        {            if(co[i][j]==c)            {                L=max(j+1,L);                break;            }        }        if(i==x)        {            sum += (n - x + 1) * (y - L + 1) * (R - y + 1);            continue;        }        for(int j=y+1;j<=min(m,R);j++)        {            if(co[i][j]==c)            {                R=min(R,j-1);                break;            }        }        sum+=(y-L+1)*(R-y+1)*(n-x+1);    }    return sum;}int main(){    int t;    //freopen("data.in", "r", stdin);    //freopen("data.out", "w", stdout);    scanf("%d",&t);    while(t--)    {        memset(co,0,sizeof co);        scanf("%d %d",&n,&m);        for(int i=1;i<=n;i++)        {            for(int j=1;j<=m;j++)            {                scanf("%d",&co[i][j]);            }        }        ll sum1=0,sum2=0;        for(int i=1;i<=n;i++)        {            for(int j=1;j<=m;j++)            {                sum1+=solve(i,j);                sum2+=i*j;            }        }        printf("%.9f\n",sum1*1.0/sum2);    }}
原创粉丝点击