题意:对于一个使用十六进制读入的 \(01\) 矩阵,求其中 \(1\) 的连通块个数,空间限制 16MB 。\(n\le 2^{12},m\le2^{14}\)

我们认为如何读入是比较基础的内容,不作过多的介绍,具体请看代码。

离线下来怎么做

首先,如果不考虑空间限制,这题是比较简单的。我们可以直接在图上 DFS 获得 \(O(nm)\) 的做法。但是空间限制要求我们不能把全图存下来。我们就只能一行一行读入,考虑在线的做法。

在线,但不考虑空间限制

我们每次读入一行,考虑会发生什么。我们发现 DFS的本质就是 染色 。我们保存上一行的状态和颜色,读入当前一行的状态。

然后从当前行往上看。如果上一行的当前位置是 \(1\),那么它一定被涂色过了,给当前格子涂上它的颜色。从它开始往左右两边循环涂色(在这一层扩张连通块),如果遇到了 \(0\) 就结束, 如果遇到了别的颜色,那么就意味着当前的颜色和另外的颜色会合并起来。

最后,有些格子可能不能从上一行继承颜色,就需要新建颜色给它们。

先不考虑空间限制,考虑如何在线维护。

我们可以给所有的颜色开一个并查集,每次在并查集上维护两种颜色是否相同,合并两种颜色。最后直接扫描整个并查集,看其中有多少个等价类。

注意实现细节,为了每个点都只被扫到一次,我们 优先用左侧的颜色覆盖右边的 ,当覆盖到一个可以从上方继承别的颜色的格子的时候,进行颜色合并。

但是颜色的数量可能达到 \(O(nm)\) 的级别,不能直接开并查集,考虑优化。

在线且考虑空间复杂度

我们发现,执行到当前行, 有效的颜色(可能对下面产生影响的)只有前一行的所有颜色,总数是 \(O(m)\) 的级别。 我们可以每次重新给颜色编号,例如,当前前一行的颜色是 1 2 5 6 7 ,我们直接将其改成 1 2 3 4 5 ,后面新增颜色的时候就从 6 开始。

如果有相同颜色呢?用 map 吗?带 \(\log\) 基本就挂了。我们发现,每行增加的颜色数量也是 \(O(m)\) 的,所以颜色的值域是 \(O(m)\) 的。我们就可以直接用长度 \(2m\) 的数组暴力维护原先值域的所有颜色到新值域的映射,\(O(1)\) 检查 当前值映射是否存在,从而决定是否建立新的映射。

因此,我们就可以只开 \(O(m)\) 的并查集数组而非 \(O(nm)\) 的。注意并查集每次都要初始化(因为我们是在 滚动地处理问题 )。并且,因为每次的并查集不往下继承,即使上一层属于同一并查集的结果,下面也会认为他们是不同的,所以 每次运算结束之后要进行推平。

具体而言,当前在并查集上, 12 是同一集合内的。但是如果到了下面一层,因为当前的信息丢失,下一层就会认为 12 是不同颜色。因此,我们最后把所有的 color[i] 更改成 find(color[i]) ,就可以保证下一次不会把同样的颜色辨认成不同的。 (相当于路径压缩)

如何计算答案呢?我们发现,每当我们分配一个颜色,就会增加一个连通块。 合并两种颜色,其中一个颜色就被删除,减去一个连通块。 可以直接在合并的同时计算。

时间复杂度优化

而直接实现的做法会带一个并查集的 \(\log\),会挂。

众所周知,如果我们同时在并查集上使用启发式合并和路径压缩,就可以把并查集的复杂度优化到 \(O(\alpha(n))\) 。而 \(\alpha(m)\) 是很小的,能有 \(4\) 就顶了天了。于是,我们就得到了一个 \(O(nm\alpha(m))\) 的做法,空间是 \(O(m)\) 的,足以通过这道题。

代码

#define rd(i,n) for(int i=0;i<n;i++)
#define rp(i,n) for(int i=1;i<=n;i++)
#define st string
#define pb push_back
typedef long long ll;
int n,m;
int a[20005],b[20005],cnt,cb[20005],c[20005],ans,ers[20005];
int fa[40005],sz[40005],app[40005],lstcnt;
inline void getlne(){
st s;
cin>>s;
//滚动
rp(i,m)b[i]=a[i],cb[i]=c[i],c[i]=0;
//读入
rd(i,m/4){
int val=0;
if(s[i]>='A')val=10+s[i]-'A';
else val=s[i]-'0';
a[4*i+1]=(val>>3&1);
a[4*i+2]=(val>>2&1);
a[4*i+3]=(val>>1&1);
a[4*i+4]=(val>>0&1);
}
//建立旧的值域到新的值域的映射
lstcnt=cnt,cnt=0;
rp(i,m)if(cb[i]){
if(app[cb[i]]){
cb[i]=app[cb[i]];
}else {
int cur=++cnt;
app[cb[i]]=cur;
cb[i]=cur;
}
}
//记得清空映射,初始化并查集
rp(i,lstcnt)if(app[i])app[i]=0;
rp(i,cnt)fa[i]=i,sz[i]=1;
}
inline void merge(int x,int y){
if(x==y)return;
else ans--;//在这里维护答案
if(sz[x]>sz[y])sz[x]+=sz[y],fa[y]=x;
else sz[y]+=sz[x],fa[x]=y;
}
inline int head(int x){
return fa[x]==x?x:fa[x]=head(fa[x]);
}
inline void solve(){
//先考虑有颜色继承的往左右覆盖
rp(i,m)if(a[i]&&b[i]&&!c[i]){
int l=i,r=i;c[i]=cb[i];
while(l>1&&a[l-1])l--,c[l]=c[i];
while(r<m&&a[r+1]){
r++;
//合并颜色
if(cb[r]&&cb[r]!=c[i])merge(head(cb[r]),head(c[i]));
c[r]=c[i];
}
i=r;
}
//颜色推平
rp(i,m)if(c[i])c[i]=head(c[i]);
//新分配颜色
rp(i,m)if(a[i]&&!c[i]){
c[i]=++cnt;ans++;
while(i<m&&a[i+1])i++,c[i]=c[i-1];
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m;
rp(i,n){
getlne();
solve();
}
cout<<ans<<endl;
return 0;
}
//Crayan_r

CF884E - Binary Matrix的更多相关文章

  1. A.Kaw矩阵代数初步学习笔记 3. Binary Matrix Operations

    “矩阵代数初步”(Introduction to MATRIX ALGEBRA)课程由Prof. A.K.Kaw(University of South Florida)设计并讲授. PDF格式学习笔 ...

  2. Educational Codeforces Round 20 A. Maximal Binary Matrix

    A. Maximal Binary Matrix time limit per test 1 second memory limit per test 256 megabytes input stan ...

  3. 【leetcode】1284. Minimum Number of Flips to Convert Binary Matrix to Zero Matrix

    题目如下: Given a m x n binary matrix mat. In one step, you can choose one cell and flip it and all the ...

  4. 【leetcode】1253. Reconstruct a 2-Row Binary Matrix

    题目如下: Given the following details of a matrix with n columns and 2 rows : The matrix is a binary mat ...

  5. LeetCode 1284. Minimum Number of Flips to Convert Binary Matrix to Zero Matrix (最少翻转次数将二进制矩阵全部置为0)

    给一个矩阵mat,每个格子都是0或1,翻转一个格子会将该格子以及相邻的格子(有共同边)全部翻转(0变为1,1变为0) 求问最少需要翻转几次将所有格子全部置为0. 这题的重点是数据范围,比赛结束看了眼数 ...

  6. uva12534 Binary Matrix 2(最小费用最大流)

    http://blog.csdn.net/qq564690377/article/details/17082055 做的时候觉得明显是费用流,但是真的不知道怎么建图,看了上面的博客会稍微清晰一点.后面 ...

  7. Maximal Binary Matrix CodeForces - 803A (贪心+实现)

    题目链接 题意有点坑: 给你一个N*N的矩阵,让你填入K个1,使之整个矩阵关于左上到右下的对角线对称,并且这个要求这个矩阵的字典序最大. 对矩阵的字典序的定义是从每一行的第一个元素开始比较,大着为字典 ...

  8. CodeForces 803A Maximal Binary Matrix

    枚举. 枚举对角线上放多少个$1$,剩余的贪心放,更新答案. #include <iostream> #include <cstdio> #include <cstrin ...

  9. LeetCode 1091. Shortest Path in Binary Matrix

    原题链接在这里:https://leetcode.com/problems/shortest-path-in-binary-matrix/ 题目: In an N by N square grid, ...

  10. Codeforces 884E E. Binary Matrix

    题 OvO http://codeforces.com/contest/884/problem/E 884e 解 考虑并查集,每个点向上方和左方的点合并,答案即为1的总数减去需要合并的次数 由于只有1 ...

随机推荐

  1. 浏览器DevTools使用技巧

    我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值. 本文作者:正则 作为一名前端开发人员,平时开发中使用最多的就是 Ch ...

  2. 当我们说大数据Hadoop,究竟在说什么?

    前言 提到大数据,大抵逃不过两个问题,一个是海量的数据该如何存储,另外一个就是那么多数据该如何进行查询计算呢.好在这些问题前人都有了解决方案,而Hadoop就是其中的佼佼者,是目前市面上最流行的一个大 ...

  3. .net6制作让同事不能上网的arp欺骗工具

    摘一段来自网上的arp欺诈解释:ARP欺骗(ARP spoofing),又称ARP毒化(ARP poisoning,网络上多译为ARP病毒)或ARP攻击,是针对以太网地址解析协议(ARP)的一种攻击技 ...

  4. python基础-常用内置包

      内置包是python自带的一些功能模块,有需求时可以在自己文件中直接导入使用. 1.datetime包   python中的时间包,可以在业务开发中辅助我们处理时间信息: # datetime可以 ...

  5. Windows11家庭中文版——启用或关闭Windows功能中找不到hyper解决方法

    Windows11家庭中文版找不到hyper解决方法: 1.将如下代码添加到记事本中,并另存为[Hyper-V.bat]文件,代码如下: pushd "%~dp0" dir /b ...

  6. python 爬站长素材网页图片

    一.我们要用python第三方库: import requests import re 二.找到自己感兴趣的网页图片: for i in range(1,2): url = "https:/ ...

  7. anaconda peompt 、labalimg 数据标注

    安装anaconda,进行数据标注 1.安装前准备:下好安装包和所需文件 https://www.aliyundrive.com/s/XyH2JQ5TjCz 提取码: 3c2w 2.运行anacond ...

  8. 关于asp.net mvc的控制器的依赖注入思考及对StructureMap依赖注入框架的简单实践笔记

    写在前面: 依赖注入这个玩意很多人其实都接触过,但可能没有细究其中的原理. 比如Controller的构造函数中,只要你传入一些接口,应用自动就给你处理了创建的过程,无需你手动去new 一个实例并穿进 ...

  9. 华为云Stack新版发布:构筑行业云底座,共创行业新价值

    摘要:在以"政企深度用云,释放数字生产力"为主题的华为云Stack战略暨新品发布会上,华为云提出深度用云三大关键举措,并发布华为云Stack 8.2版本,以智能进化推动创造行业新价 ...

  10. JS原生上传文件,读取文件格式,控制文件只可以上传某些格式,并使用fileReader转换格式

    本文为代码片段记录,方便后期使用哇! <!DOCTYPE html> <html lang="en"> <head> <meta char ...