1 条题解
-
0
前言:感觉大佬们只讲了怎么做,没写为什么要这么做
,不适合我这种蒟蒻理解。所以我写了篇适合蒟蒻食用的题解。题意
楼梯:左侧齐平,右侧不能往左陷
思路
根据题意,我们先记 ,代表 右侧有几个 。
然后,把模板横过来,发现题目就是让我们找最长不下降子串的每一项之和(不过有很多行)。
大体思路有了,现在要实现找每行(横着的)最长不下降子串。
首先,我们从右往左一列一列看(横着的从上到下),记录这格的 能从下往上延续多少格,记延续的格数 (由于每行是单独的,行内计算可以省略 ),那么这个 能做出 格贡献(请搭配题图理解)。
然后,我们从上往下(横着的从左到右)遍历,记以当前格为左下角(正看)的楼梯的面积为 ,。也就是当前 做的贡献加上前面它结束贡献的地方的贡献。以样例为例, 时,两格的楼梯持续了两个长度,那么 。
不过直接模拟时间复杂度是 ,会 TLE,我们要优化一下。
我们寻找最长不下降子串的特点是:从右到左,找第一个小于 的地方。所以我们能想到用单调栈来优化。单调栈能把时间优化成 。
我们的思路到此结束,接下来就要开始写代码啦~
代码
#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:纠正一处笔误。
- 1
信息
- ID
- 9579
- 时间
- 500ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者