[思维]最大矩阵

题目描述

现在有一个 n × m n \times m n×m 的 01 01 01 矩阵,矩阵的行与行可以互相交换,我们现在想知道在一个最优的交换方案中,其中最大的全 1 1 1 子矩阵能有多大。

输入格式

第一行两个整数 n , m n, m n,m。

接下来 n n n 行,每行一个长度为 m m m 的 01 01 01 字符串,描述这个 01 01 01 矩阵。

输出格式

一个数,即最大的全 1 1 1 子矩阵面积。

样例

样例输入1:

复制代码
2 2
10
11

样例输出1:

复制代码
2

样例输入2:

复制代码
4 3
100
011
000
101

样例输出2:

复制代码
2

数据范围

对于 30 % 30\% 30% 的数据, n , m ≤ 10 n, m \le 10 n,m≤10。

对于 70 % 70\% 70% 的数据, n , m ≤ 1000 n, m \le 1000 n,m≤1000。

对于 100 % 100\% 100% 的数据, n , m ≤ 5000 n, m \le 5000 n,m≤5000。

题解

对于 30 % 30\% 30% 的数据,直接枚举左上,右上,左下,右下四个端点,判断内部是否全 1 1 1 即可。

如果用前缀和优化,可以得到 40 40 40 分。

考虑固定左端点,枚举右端点,看有多少行满足条件,计算即可。

先预处理每行每个位置向后延申的最大 1 1 1 序列的结尾,用双指针求。

接下来枚举左右端点,看每行从左端点开始是否大于右端点。

复杂度为 Θ ( n × m ) \Theta(n \times m) Θ(n×m),但是还是 70 70 70 分,常数大了。

cpp 复制代码
输入 n, m 和数组 a
//预处理每个位置向后延申的最大1序列的结尾 
for(int i = 1; i <= n; ++ i){//第 i 行
	int l = 0, r = 1;
	while(l <= r && r <= m){
		++ l;
		r = max(r, l);
		if(a[i][l] == 0){
			f[i][l] = -1;
			continue;
		}
		while(a[i][r] == 1){
			++ r;
		}
		-- r;
		f[i][l] = r;
	} 
}
//l 为左端点
int l = 0, ans = 0;
while(l < m){
	++ l;
	//找到能扩展的最大右端点
	int s = 0;
	for(int i = 1; i <= n; ++ i){
		s = max(s, f[i][l]);
	} 
	//记录 prv 进行优化,l 到 r 和 l 到 r + 1 是单调不增的,如果当前长度乘上上一个的数量小于答案,返回
	int prv = n;
	for(int j = l; j <= s; ++ j){
		if((j - l + 1) * prv <= ans){
			continue;
		}
		//统计有多少行满足条件
		int sum = 0;
		for(int i = 1; i <= n; ++ i){
			if(f[i][l] >= j){
				++ sum;
			}
		}
		prv = sum;
		ans = max(ans, sum * (j - l + 1));
	}
}
printf("%d\n", ans);

进行常数优化。

  1. 舍弃预处理数组,在输入时直接统计当前行连续长度的个数。
  2. 输入时不要用 % 1 d \%1d %1d,直接输入字符数组,会快很多。
cpp 复制代码
for(int i = 1; i <= n; ++ i){
	scanf("%s", a);
	//连续长度统计
	int s = 0;
	for(int j = 1; j <= m; ++ j){
		if(a[j - 1] == '1'){
			++ s;
			fl[j][s] ++;
		}
		else{
			s = 0;
		}
	}
}
int l = 0, ans = 0;
while(l < m){
	++ l;
	int s = 0;
	//从 m 开始,比 i 长度长的就不用重新统计了
	for(int i = m; i >= 0; -- i){
		s += fl[l][i];
		if(s * i > ans){
			ans = s * i;
		}
	}
}
printf("%d\n", ans);
相关推荐
凡人叶枫5 小时前
Effective C++ 条款30:透彻了解 inlining 的里里外外
linux·开发语言·c++·嵌入式开发·effective c++
noipp5 小时前
推荐题目:洛谷 P10907 [蓝桥杯 2024 国 B] 蚂蚁开会
c语言·c++·算法·编程·洛谷
学逆向的6 小时前
C++纯虚函数
开发语言·c++·网络安全
程序员二叉6 小时前
【JUC】线程池全套深度详解|参数|流程|拒绝策略|调优|异常处理
java·开发语言·jvm·算法·面试·juc
青山木6 小时前
Hot 100 --- 轮转数组
java·数据结构·算法
徐小夕7 小时前
Loop Engineering 深度解析与实战指南(全网最全)
前端·算法·github
凡人叶枫7 小时前
Effective C++ 条款22:将成员变量声明为 private
linux·开发语言·c++
北域码匠8 小时前
SHA-1算法:安全哈希原理与应用解析
算法·c#·哈希算法
坚果派·白晓明8 小时前
【鸿蒙PC】SDL3 移植:AtomCode Skills 4 步速通多媒体库适配
c++·华为·ai编程·harmonyos·atomcode·c/c++三方库
手写码匠8 小时前
手写 GraphRAG:从零实现图增强检索增强生成系统
人工智能·深度学习·算法·aigc