【蓝桥杯】统计子矩阵【C++】

文章介绍了两种解决子矩阵和超过特定值K问题的方法:一是二维前缀和结合二分查找,但只能得到部分分数;二是使用一维前缀和配合双指针滑动窗口,能更高效地找到所有满足条件的子矩阵。后者通过枚举上边界、下边界和右边界,动态调整左边界以保持子矩阵和小于K,计算出子矩阵数量。
摘要由CSDN通过智能技术生成

在这里插入图片描述

暴力题解

乍一看题目的解体方法是,二维前缀和+二分查找,但是这样的话只能拿到70%的分

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD = 1000000007;
const int N = 505;

ll m, n, k;
ll a[N][N];
ll ans = 0;

ll getsum(int i, int j, int x, int y) {
	return a[x][y] - a[i - 1][y] - a[x][j - 1] + a[i - 1][j - 1];
}

int main() {
	cin >> m >> n >> k;
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j <= n; j++) {
			cin >> a[i][j];
			a[i][j] += a[i - 1][j] - a[i - 1][j - 1] + a[i][j - 1];
		}
	}
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j <= n; j++) {
			if (getsum(i, j, i, j) > k) continue;
			for (int x = i; x <= m; x++) {
				int l = j, r = n;
				while (l < r) {
					int mid = (l + r + 1) >> 1;
					if (getsum(i, j, x, mid) > k) r = mid - 1;
					else l = mid;
				}
				if (getsum(i, j, x, l) > k) break;
				ans += l - j + 1;
			}
		}
	}
	cout << ans << endl;
	return 0;
}


真正题解(一维前缀+双指针滑动窗口)

我们枚举上边界和下边界,即当前枚举矩阵是处在第x行(上边界),和y(下边界)之间的。接着枚举矩形的右端点,我们可以发现,每次当右端点向右移动的时候,矩形的面积是单调递增的,此时如果矩形的面积大于K,则不合要求,固定右端点,此时我们将当前矩形的左端点也向右移动,矩形的面积单调变小,直到举行面积再次小于K,停止移动。

那么我们怎么才能得到子矩阵的数目呢?
其实就是右边界到达临界值的时候,减去左边界再加1,得到的数就是我们循环一次能得到的子矩阵的数量。

#include<bits/stdc++.h>
using namespace std;
int n,m,k;
const int maxn=505;
int g[maxn][maxn];//原数组
int sum[maxn][maxn];//前缀和数组

int main()
{
	ios::sync_with_stdio(false) ;//这一行代码的作用是给cin和cout加速 

	cin>>n>>m>>k;
	for(int i = 1; i <= n ; i++)
	{
		for(int j = 1; j <= m ; j++)
		{
			cin>>g[i][j];
			// 按列的前缀和放入sum数组中
			sum[i][j] = g[i][j] + sum[i-1][j];
		}
	}
//  验证sum数组中的数是不是按列的前缀和
//	for(int i = 1; i <= n ; i++)
//	{
//		for(int j = 1; j <= m ; j++)
//		{
//			cout<<sum[i][j]<<' ';
//			
//		}
//		cout<<endl;
//	}
	
	long long m_count = 0;
	//把和想象成四个点围成的矩形的面积
	for(int x = 1; x <= n; x++)//x是上边界
	{
		for(int y = x; y <= n; y++)//y是下边界
		{
			for(int r = 1, l = 1, s = 0; r <= m; r++)//r是右边界,l是左边界
			{
				
				s += sum[y][r] - sum[x - 1][r];
				while(s > k && l < r)
				{
					s = s - sum[y][l] + sum[x - 1][l];
					l++;
				}
				if(s <= k){
					m_count += r - l + 1;
				}
			}
		}
	}
	
	cout << m_count << endl;

	return 0;
	
}

总结

在做这一题之前最好去学习一下一维前缀和二维前缀的算法,搞清楚前缀和是怎么得出来的,在纸上写写画画,不然很难理解。

CentOS是一款流行的Linux操作系统,适合部署各种类型的项目。若依是一个基于SpringBoot框架开发的通用权限管理系统,采用前后端分离的架构。下面将详细讲述如何在CentOS上部署若依前后端分离项目。 1.安装Java环境。 若依是基于Java开发的系统,所以需要安装Java环境。可通过以下命令进行安装: yum install java-1.8.0-openjdk-devel 2.安装MySQL数据库。 若依需要使用MySQL数据库进行数据存储。可通过以下命令进行安装: yum install mysql-server mysql 3.安装Nginx。 Nginx是一款高性能的Web服务器,也是实现前后端分离的关键组件。可通过以下命令进行安装: yum install nginx 4.部署若依后端。 将若依的后端代码部署到CentOS服务器上,并在MySQL数据库中创建对应的数据库和数据表。在application-*.yml配置文件中设置数据库连接信息和端口号等相关配置。 5.部署若依前端。 将若依前端代码部署到Nginx服务器上,并在Nginx配置文件中设置代理转发规则。例如,将/api开头的请求转发到后端的对应接口上。 6.启动服务。 分别启动后端服务和Nginx服务,可通过Systemd进行管理。在后端接口正常提供服务的情况下,可以通过浏览器访问Nginx服务器的IP地址和端口号,查看前端界面。 总之,通过上述步骤可以在CentOS服务器上成功部署若依前后端分离项目,实现良好的用户体验和数据存储。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值