专栏文章

题解:P12501 「ROI 2025 Day1」奥林匹克楼梯

P12501题解参与者 3已保存评论 2

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
2 条
当前快照
1 份
快照标识符
@minqg1mb
此快照首次捕获于
2025/12/02 06:40
3 个月前
此快照最后确认于
2025/12/02 06:40
3 个月前
查看原文
前言:感觉大佬们只讲了怎么做,没写为什么要这么做 ,不适合我这种蒟蒻理解。所以我写了篇适合蒟蒻食用的题解。

题意

楼梯:左侧齐平,右侧不能往左陷

思路

根据题意,我们先记 hi,jh_{i,j},代表 (i,j)(i,j) 右侧有几个 11
然后,把模板横过来,发现题目就是让我们找最长不下降子串的每一项之和(不过有很多行)。
大体思路有了,现在要实现找每行(横着的)最长不下降子串。
首先,我们从右往左一列一列看(横着的从上到下),记录这格的 hi,jh_{i,j} 能从下往上延续多少格,记延续的格数 lil_{i}(由于每行是单独的,行内计算可以省略 jj),那么这个 hi,jh_{i,j} 能做出 li×hi,jl_i \times h_{i,j} 格贡献(请搭配题图理解)。
然后,我们从上往下(横着的从左到右)遍历,记以当前格为左下角(正看)的楼梯的面积为 sis_isi=sili+li×hi,js_i = s_{i - l_i} + l_i \times h_{i,j}。也就是当前 hi,jh_{i,j} 做的贡献加上前面它结束贡献的地方的贡献。以样例为例,j=2j = 2 时,两格的楼梯持续了两个长度,那么 s4=s2+l5×h5,2s_4 = s_2 + l_5 \times h_{5,2}
不过直接模拟时间复杂度是 O((hw)2)O((hw)^2),会 TLE,我们要优化一下。
我们寻找最长不下降子串的特点是:从右到左,找第一个小于 hi,jh_{i,j} 的地方。所以我们能想到用单调栈来优化。单调栈能把时间优化成 O(hw)O(hw)
我们的思路到此结束,接下来就要开始写代码啦~

代码

CPP
#include <bits/stdc++.h>
using namespace std;
vector<vector<bool>> a;
vector<vector<int>> h;	// 以(i,j)为准,右边有多少个1
vector<int> s,l;
// s:对于每个j,以i为左下角的楼梯的最大格数
// l:对于每个j,h[i][j]能向上持续多远(楼梯定义)
int mx;
int main(int argc, char **argv){
	int n,m;
	cin >> n >> m;
	a = vector<vector<bool>>(n + 1,vector<bool>(m + 1));
	h = vector<vector<int>>(n + 1,vector<int>(m + 1));
	s = l = vector<int>(n + 1);
	for (int i = 1;i <= n;i++){
		string s;
		cin >> s;
		for (int j = 1;j <= m;j++){
			a[i][j] = s[j - 1] - '0';
		}
	}
	for (int i = 1;i <= n;i++){
		h[i][m] = a[i][m];
		for (int j = m - 1;j > 0;j--){
			if (a[i][j])	h[i][j] = h[i][j + 1] + 1;
		}
	}
	for (int j = m;j > 0;j--){
		// for (int i = n;i > 0;i--){
		// 	int k = i - 1;
		// 	while (k >= 0 && h[k][j] >= h[i][j])	k--;
		// 	l[i] = i - k;
		// }
		// for (int i = 1;i <= n;i++){
		// 	s[i] = s[i - l[i]] + l[i] * h[i][j];
		// 	mx = max(mx,s[i]);
		// }
		stack<int> st;
		for (int i = n;i > 0;i--){
			l[i] = i;	// 默认能持续到最顶上
			while (!st.empty() && h[st.top()][j] > h[i][j]){
				l[st.top()] = st.top() - i;
				st.pop();
			}
			st.push(i);
		}
		for (int i = 1;i <= n;i++){
			s[i] = s[i - l[i]] + l[i] * h[i][j];
			mx = max(mx,s[i]);
		}
	}
	cout << mx;
	return 0;
}
upd 2025.10.7:纠正一处笔误。

评论

2 条评论,欢迎与作者交流。

正在加载评论...