题意:对于一个使用十六进制读入的 \(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. C++编程笔记(QT)

    目录 入门基础 模态对话框 消息提示框(messagebox) 文件和目录 字体选择框 输入对话框 进度条 工具栏 控件布局 Windows托盘案例 控件 button 下拉菜单按钮 `radioBu ...

  2. pycharm全局搜索

    方法有:1.使用[Ctrl+N]快捷键按文件名搜索py文件: 2.使用[Ctrl+shift+N]快捷键按文件名搜索所有类型的文件: 3.使用[ctrl+shift+f]快捷全局字符串搜索: 3.使用 ...

  3. Python全栈工程师之从网页搭建入门到Flask全栈项目实战(6) - Flask表单的实现

    1.表单介绍 1.1.表单知识回顾 常见的表单元素: 表单标签<form> action:表单提交的URL地址 method:表单请求的方式(GET/POSt) enctype:请求内容的 ...

  4. SpringCloud微服务框架复习笔记

    SpringCloud微服务框架复习笔记 什么是微服务架构? 微服务是一种软件开发技术,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调.互相配合,为用户提供最终价值.每个服务运行在其独立的进 ...

  5. 有关WCH的CH42x以及CH45x选型,常见问题处理方法

    南京沁恒微电子的CH45x系列为数码管.按键驱动芯片. CH42x系列为IO扩展芯片.CH422和CH423除了支持的OC数量有一些区别,在单片机的驱动上,并没有任何区别,驱动CH423的代码是可以套 ...

  6. 关于Git在Visual studio及Git Bush中的日常操作教程,有图有说明,会一直更新本页内容... (Git相对SVN具有更加安全的分布式存储, 分支版本之间切换秒级速度, 分支版本强大灵活等特点)

    >安装命令行和TortoiseGit UI程序. <git bash的安装> https://git-scm.com/downloads <windows可视化工具 Torto ...

  7. Git和Maven的学习笔记

    Git 1.Git简介 Git 是一个免费的.开源的分布式版本控制系统,可以快速高效地处理从小型到大型的各种 项目. Git 易于学习,占地面积小,性能极快. 它具有廉价的本地库,方便的暂存区域和多个 ...

  8. [编程基础] Python中*args和**kwargs参数的使用

    本文主要介绍Python中*args和**kwargs参数的使用 文章目录 1 使用 2 拓展 3 参考 1 使用 在Python中,定义函数时可以使用两个特殊符号,以允许它们接受可变数量的参数.这两 ...

  9. Springboot启动时加载

    @Component public class SpringBootInitialization1 implements ServletContextListener { @Override publ ...

  10. [超详细] [效能工具]Typora+PicGo+Github免费图床快速搭建,提升技术文档输出效率

    一.前言 在我们日常的学习和工作中,我们经常需要进行写作.尤其对于我们程序技术人员而言,工作中的技术方案文档或者接口文档等,都是经常需要用上的. 那么如果没有一个高效的工具,去帮助我们记录和创作,这将 ...