CF884E - Binary Matrix
题意:对于一个使用十六进制读入的 \(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)\) 的。注意并查集每次都要初始化(因为我们是在 滚动地处理问题 )。并且,因为每次的并查集不往下继承,即使上一层属于同一并查集的结果,下面也会认为他们是不同的,所以 每次运算结束之后要进行推平。
具体而言,当前在并查集上, 1
和 2
是同一集合内的。但是如果到了下面一层,因为当前的信息丢失,下一层就会认为 1
和 2
是不同颜色。因此,我们最后把所有的 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的更多相关文章
- A.Kaw矩阵代数初步学习笔记 3. Binary Matrix Operations
“矩阵代数初步”(Introduction to MATRIX ALGEBRA)课程由Prof. A.K.Kaw(University of South Florida)设计并讲授. PDF格式学习笔 ...
- 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 ...
- 【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 ...
- 【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 ...
- LeetCode 1284. Minimum Number of Flips to Convert Binary Matrix to Zero Matrix (最少翻转次数将二进制矩阵全部置为0)
给一个矩阵mat,每个格子都是0或1,翻转一个格子会将该格子以及相邻的格子(有共同边)全部翻转(0变为1,1变为0) 求问最少需要翻转几次将所有格子全部置为0. 这题的重点是数据范围,比赛结束看了眼数 ...
- uva12534 Binary Matrix 2(最小费用最大流)
http://blog.csdn.net/qq564690377/article/details/17082055 做的时候觉得明显是费用流,但是真的不知道怎么建图,看了上面的博客会稍微清晰一点.后面 ...
- Maximal Binary Matrix CodeForces - 803A (贪心+实现)
题目链接 题意有点坑: 给你一个N*N的矩阵,让你填入K个1,使之整个矩阵关于左上到右下的对角线对称,并且这个要求这个矩阵的字典序最大. 对矩阵的字典序的定义是从每一行的第一个元素开始比较,大着为字典 ...
- CodeForces 803A Maximal Binary Matrix
枚举. 枚举对角线上放多少个$1$,剩余的贪心放,更新答案. #include <iostream> #include <cstdio> #include <cstrin ...
- LeetCode 1091. Shortest Path in Binary Matrix
原题链接在这里:https://leetcode.com/problems/shortest-path-in-binary-matrix/ 题目: In an N by N square grid, ...
- Codeforces 884E E. Binary Matrix
题 OvO http://codeforces.com/contest/884/problem/E 884e 解 考虑并查集,每个点向上方和左方的点合并,答案即为1的总数减去需要合并的次数 由于只有1 ...
随机推荐
- 【基础语法规范】BC1:Hello Nowcoder
语言1:Java public class Main{ public static void main(String[] args){ System.out.println("Hello N ...
- 【面试真题】ThoughtWorks-编程结对技术面试(一面)-2022年2月11日
一.技术问题 1.Hbase (1)介绍 (2)项目中是否有用到 于:存大量数据(千万),考虑性能,方便进行数据处理,对其进行分析 自己:ADS层和Flink的数据,DWD计算出的的中间层数据存入DW ...
- 从零入门项目集成Karate和Jacoco,配置测试代码覆盖率
解决问题 在SpringBoot项目中,如何集成Karate测试框架和Jacoco插件.以及编写了feature测试文件,怎么样配置才能看到被测试接口代码的覆盖率. 演示版本及说明 本次讲解,基于Sp ...
- Pytorch框架详解之一
Pytorch基础操作 numpy基础操作 定义数组(一维与多维) 寻找最大值 维度上升与维度下降 数组计算 矩阵reshape 矩阵维度转换 代码实现 import numpy as np a = ...
- 手写promise解决回调地狱问题
在介绍promise之前我们先来看一段代码: 根据案例我们可以看出,这段代码可以无限的嵌套下去,但是每嵌套一层,代码的运行就会降低,而解决回调地狱最好的办法就是new promise 一.什么是 pr ...
- 04-CURD
Insert @Test//测试插入 public void insertTest(){ User user = new User(); user.setName("wsk"); ...
- CTFshow——funnyrsa1的wp理解
题目如下: 题目分析: 拿到题,发现给的e不常规,p1和p2相等,有两个不同n,两个不同c和两个不同e.给定两个密文的情况下,通常需要找到两者之间存在的关系,"合并"密文求解才能得 ...
- TypeScript 前端工程最佳实践
作者:王春雨 前言 随着前端工程化的快速发展, TypeScript 变得越来越受欢迎,它已经成为前端开发人员必备技能. TypeScript 最初是由微软开发并开源的一种编程语言,自2012年10月 ...
- 迁移学习(DANN)《Domain-Adversarial Training of Neural Networks》
论文信息 论文标题:Domain-Adversarial Training of Neural Networks论文作者:Yaroslav Ganin, Evgeniya Ustinova, Hana ...
- @Transactional事务回滚异常:Transaction rolled back because it has been marked as rollback-only
问题描述 事务设置手动回滚:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() 代码需要返回比较友好的提示,但t ...