HDU6052 To my boyfriend

【题目链接】
http://acm.hdu.edu.cn/showproblem.php?pid=6052

题目意思

给比个矩阵,矩阵中每个格子都有一个数字,同一数字代表同一种颜色,问你所有子矩阵种颜色个数总和。

解题思路

对于每个子矩阵含多多少颜色不好判断,所有判断没个颜色占子矩阵个数。而同种颜色判断从上到下,从左到右。没判断完一个位子上所占矩阵个数,就标记,防止下面同种颜色重复计算。

代码部分

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL w[105][105];//保存原理图
int vis[105],m,n;//vis[j] = i 表示将第j列用i颜色标记
vector<int> y[105];//y[i]用来表示第i行有哪些列被标记过
vector<pair<int,int> > C[10005];//用来保存所有颜色出现的坐标
LL calc(int col)
{
    memset(vis,0,sizeof(vis));
    LL sum = 0;
    for(auto now:C[col])
    {
        int ni = now.first,nj = now.second;//保存当前颜色的坐标
        for(int i = 1; i <= m; i++)//对于每次找那些坐标被标记过之间都应该将此数组清零,防止以前数据对这次查找有影响
            y[i].clear();
        for(int i=1; i<=m; i++)
            if(vis[i])
                y[vis[i]].push_back(i);

        int yl = 1,yr = m,flag = 0;
        for(int i = ni; i>=1; i--)
        {
            //枚举所有可能的上边界
            vector<int>::iterator it;
            for(it = y[i].begin(); it!=y[i].end(); it++)
            {
                //如果第i行有被标记的,找出被标记的列数,并更新左右区间
                int yy = *it;
                if(yy<nj)
                    yl = max(yl,yy+1);
                else if(yy > nj)
                    yr = min(yr,yy-1);
                else
                {
                    //如果这个点的正上方有与它颜色相同的点结束循环
                    flag = 1;
                    break;
                }
            }
            if(flag) break;
            sum += (n-ni+1)*(nj-yl+1)*(yr-nj+1);//计算已ii上上边界的方案数,
        }
        vis[nj] = ni;//将第nj列标记为ni方边利用y数组更新边界
    }
    return sum;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&n,&m);
        for(int i=0; i<=n*m; i++)
            C[i].clear();
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
            {
                scanf("%lld",&w[i][j]);
                C[w[i][j]].push_back(make_pair(i,j));//记录每种颜色的坐标
            }
        LL sum = 0;//记录不同颜色子矩阵的个数
        for(int i=0; i<=n*m; i++)
            if(!C[i].empty())
            {
                sort(C[i].begin(),C[i].end());//将每种颜色按坐标先行优先再列优先排序
                sum += calc(i);
            }
        LL num = n*(n+1)*m*(m+1)/4;//子矩阵的个数
        double ans = (sum*1.0)/num;
        printf("%.9lf\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值