题目链接:Atcoder 或者 洛谷

对于解决二维区间内的最值类型问题,我们常常有一类特别好用的方法,就是悬线法,它可以看做是单调栈的子集,但更加好理解和书写。

对于悬线法,我们有一个常见的模型,找出面积最大的符合题意的最大的矩形:

例题 P4147 玉蟾宫。对于悬线法而言,我们需要理解什么是悬线:

如图所示,我们可以很容易的从第 \(1\) 行往第 \(i\) 行更新的同时,维护从当前行往上满足的最长悬线,在例题当中,则为从当前位置往上的最长连续是 \(F\) 的段。对于以 \(2\) 号位置的上悬线作为高的最优矩形,我们显然要找到它的左右悬线,如图所示,如果它左右两边的上悬线比它高,显然就能拓展出去,使得当前的这根悬线高度不会变小。绿色图形则为最终悬线更新结果。而对于 \(7\) 号上悬线而言,紫色图形则为最终结果。而左右悬线是很好维护求出来的,只需要保证上悬线不减即可,其实这个思想就是类似单调栈思想了,找到左右最先小于自身的端点,但单调栈书写这个逻辑要略显复杂一丢丢,在弹栈时去判断,我们可以用一种更为简单的方法:

更新左右悬线参照代码
forn(j, 1, m)while (L[j] > 1 and h[L[j] - 1] >= h[j])L[j] = L[L[j] - 1];
forv(j, m, 1)while (R[j] < m and h[R[j] + 1] >= h[j])R[j] = R[R[j] + 1];

从左往右更新左悬线,如果比上一个左悬线对应的上悬线还小,那就可以继续拓展到上一个左悬线可以拓展到的左悬线,右悬线就倒序遍历,同理。建议将本题反复练熟再回到原问题上

至此,回到原题,考虑如何将本题转化为基本的悬线法模型:

很显然的是,本地比较难以处理的是这个区间最小值如何处理,我们注意到区间最小值的数量不超过 \(N\),而 \(N\) 仅仅为 \(300\),所以我们可以考虑枚举最小值是多少,那么这样一来,每个点对最小值而言只有两种情况:

  1. 如果 \(a[i][j] \ge Value_{min}\),那么很显然对应的其实就是例题的 \(==F\)。

  2. 如果 \(a[i][j] < Value_{min}\),很显然就是对应的 \(==R\)。

问题转变为原例题问题,找到最大的全为 \(F\) 的矩形,然后答案为这个矩形内的数之和乘上我们枚举的最小值。而求区间和问题,可以预处理出前缀和解决。所以问题至此解决。

参照代码
#include <bits/stdc++.h>

// #pragma GCC optimize("Ofast,unroll-loops")
// #pragma GCC optimize(2) #define isPbdsFile #ifdef isPbdsFile #include <bits/extc++.h> #else #include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/trie_policy.hpp>
#include <ext/pb_ds/tag_and_trait.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/list_update_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/exception.hpp>
#include <ext/rope> #endif using namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef tuple<int, int, int> tii;
typedef tuple<ll, ll, ll> tll;
typedef unsigned int ui;
typedef unsigned long long ull;
typedef __int128 i128;
#define hash1 unordered_map
#define hash2 gp_hash_table
#define hash3 cc_hash_table
#define stdHeap std::priority_queue
#define pbdsHeap __gnu_pbds::priority_queue
#define sortArr(a, n) sort(a+1,a+n+1)
#define all(v) v.begin(),v.end()
#define yes cout<<"YES"
#define no cout<<"NO"
#define Spider ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
#define MyFile freopen("..\\input.txt", "r", stdin),freopen("..\\output.txt", "w", stdout);
#define forn(i, a, b) for(int i = a; i <= b; i++)
#define forv(i, a, b) for(int i=a;i>=b;i--)
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define endl '\n'
//用于Miller-Rabin
[[maybe_unused]] static int Prime_Number[13] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}; template <typename T>
int disc(T* a, int n)
{
return unique(a + 1, a + n + 1) - (a + 1);
} template <typename T>
T lowBit(T x)
{
return x & -x;
} template <typename T>
T Rand(T l, T r)
{
static mt19937 Rand(time(nullptr));
uniform_int_distribution<T> dis(l, r);
return dis(Rand);
} template <typename T1, typename T2>
T1 modt(T1 a, T2 b)
{
return (a % b + b) % b;
} template <typename T1, typename T2, typename T3>
T1 qPow(T1 a, T2 b, T3 c)
{
a %= c;
T1 ans = 1;
for (; b; b >>= 1, (a *= a) %= c)if (b & 1)(ans *= a) %= c;
return modt(ans, c);
} template <typename T>
void read(T& x)
{
x = 0;
T sign = 1;
char ch = getchar();
while (!isdigit(ch))
{
if (ch == '-')sign = -1;
ch = getchar();
}
while (isdigit(ch))
{
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
x *= sign;
} template <typename T, typename... U>
void read(T& x, U&... y)
{
read(x);
read(y...);
} template <typename T>
void write(T x)
{
if (typeid(x) == typeid(char))return;
if (x < 0)x = -x, putchar('-');
if (x > 9)write(x / 10);
putchar(x % 10 ^ 48);
} template <typename C, typename T, typename... U>
void write(C c, T x, U... y)
{
write(x), putchar(c);
write(c, y...);
} template <typename T11, typename T22, typename T33>
struct T3
{
T11 one;
T22 tow;
T33 three; bool operator<(const T3 other) const
{
if (one == other.one)
{
if (tow == other.tow)return three < other.three;
return tow < other.tow;
}
return one < other.one;
} T3() { one = tow = three = 0; } T3(T11 one, T22 tow, T33 three) : one(one), tow(tow), three(three)
{
}
}; template <typename T1, typename T2>
void uMax(T1& x, T2 y)
{
if (x < y)x = y;
} template <typename T1, typename T2>
void uMin(T1& x, T2 y)
{
if (x > y)x = y;
} constexpr int N = 310;
ll pre[N][N];
int h[N], L[N], R[N];//上悬线的长度,左右悬线的位置
//二维前缀和求区间和
inline ll query(const int x1, const int y1, const int x2, const int y2)
{
return pre[x2][y2] - pre[x1 - 1][y2] - pre[x2][y1 - 1] + pre[x1 - 1][y1 - 1];
} int n, m;
ll ans;
int a[N][N];
//悬线法解决最小值为val的答案
inline ll getAns(const ll val)
{
ll res = 0;
fill_n(h + 1, m, 0); //每个点上悬线长度初始化为0
forn(i, 1, n)
{
forn(j, 1, m)
{
if (a[i][j] >= val)h[j]++;//符合扩展条件,上悬线长度增加
else h[j] = 0;//不符合扩展条件,没有上悬线
L[j] = R[j] = j;//初始化当前列的左右悬线
}
forn(j, 1, m)while (L[j] > 1 and h[L[j] - 1] >= h[j])L[j] = L[L[j] - 1];
forv(j, m, 1)while (R[j] < m and h[R[j] + 1] >= h[j])R[j] = R[R[j] + 1];
forn(j, 1, m)if (h[j])uMax(res, query(i - h[j] + 1, L[j], i, R[j]) * val);//有上悬线就计算答案
}
return res;
} int mx; inline void solve()
{
cin >> n >> m;
forn(i, 1, n)
{
forn(j, 1, m)
{
cin >> a[i][j];
uMax(mx, a[i][j]), pre[i][j] = pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1] + a[i][j];
}
}
forn(i, 1, mx)uMax(ans, getAns(i));//枚举最小值
cout << ans;
} signed int main()
{
// MyFile
Spider
//------------------------------------------------------
// clock_t start = clock();
int test = 1;
// read(test);
// cin >> test;
forn(i, 1, test)solve();
// while (cin >> n, n)solve();
// while (cin >> test)solve();
// clock_t end = clock();
// cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
}
\[时间复杂度为枚举最小值乘上单次悬线法处理复杂度: \ O(value_{max} \times nm)
\]

总结:

关于悬线法而言,它常常会与二维区间的最优矩形查找有关。而我们实际上需要转化为普通悬线法的模型,需要优先考虑上悬线的扩展条件,对于某一个点而言,如果它的上悬线的扩展条件固定了,那么左右条件悬线扩展就很轻松了。建议反复将例题进行熟悉,这样遇到其他的其他的题型也可以转化为最本质的模型去解决

ABC311_g One More Grid Task 题解的更多相关文章

  1. HDU-3974 Assign the task题解报告【dfs序+线段树】

    There is a company that has N employees(numbered from 1 to N),every employee in the company has a im ...

  2. [CF11D]A Simple Task 题解

    题解 我们从最简单的思路开始考虑,首先看到题目发现\(n\)非常小,于是很容易想到状态压缩. 我们考虑比较直觉的状态,f[i][j][k]表示以i为起点,当前在j,之前去过的点状态为k的简单环的方案数 ...

  3. ZOJ - 3781 Paint the Grid Reloaded 题解

    题目大意: 给一个n*m的X O构成的格子,对一个点操作可以使与它相连通的所有一样颜色的格子翻转颜色(X—>O或O—>X),问给定的矩阵最少操作多少次可以全部变成一样的颜色. 思路: 1. ...

  4. CF 11D A Simple Task 题解

    题面 这道题的数据范围一看就是dfs或状压啦~ 本文以状压的方式来讲解 f[i][j]表示目前的节点是i,已经经历过的节点的状态为j的简单环的个数: 具体的转移方程和细节请看代码: PS:(i& ...

  5. [CF959F]Mahmoud and Ehab and yet another xor task题解

    搞n个线性基,然后每次在上一次的基础上插入读入的数,前缀和线性基,或者说珂持久化线性基. 然后一个num数组记录当时线性基里有多少数 然后每次前缀操作一下就珂以了 代码 #include <cs ...

  6. [CF959D]Mahmoud and Ehab and another array construction task题解

    解法 非常暴力的模拟. 一开始吧\(1 -> 2 \times 10^6\)全部扔进一个set里,如果之前取得数都是与原数组相同的,那么lower_bound一下找到set中大于等于它的数,否则 ...

  7. Libsvm:脚本(subset.py、grid.py、checkdata.py) | MATLAB/OCTAVE interface | Python interface

    1.脚本 This directory includes some useful codes: 1. subset selection tools. (子集抽取工具) subset.py 2. par ...

  8. SZU-A22

    Problem(A22):Party Judge InfoMemory Limit: 32768KBCase Time Limit: 10000MSTime Limit: 10000MSJudger: ...

  9. SVM应用

    我在项目中应用的SVM库是国立台湾大学林智仁教授开发的一套开源软件,主要有LIBSVM与LIBLINEAR两个,LIBSVM是对非线性数据进行分类,大家也比较熟悉,LIBLINEAR是对线性数据进行分 ...

  10. 【AtCoder】AGC029(A-E)

    A - Irreversible operation 题解 把每个B后面的W个数累加起来即可 代码 #include <bits/stdc++.h> #define fi first #d ...

随机推荐

  1. Python日常学习

    学习算法和数据结构之余开始接触python,目前正在学习语法部分,这篇blog记录下一些知识点和放一些文档 or 教程的传送门. 文档网站 Python 解释器内置函数 Python速成 from O ...

  2. 基于HTML,CSS & Javascript 实现图像的自动轮播和手动导航按钮

    不务正业的第n天(划掉 2020年年末在完成Web网页制作课程的大作战,在写代码的时候想到用HTML + CSS & Javascript制作一个图片轮播功能增强网页的功能 简单贴一下代码:注 ...

  3. 阿里云 X 森马 AIGC T恤设计大赛开启! 穿什么由你定,赢Airpods,作品定制联名T恤

    "关于宇宙,我所知道的最富诗意的事实之一就是, 我们身体中的每一个原子都曾经存在于某一颗爆发的恒星里. 组成你左手的原子和组成你右手的原子 很有可能来自不同的恒星, 而我们都是恒星的孩子, ...

  4. vue学习笔记 十九、实例完整代码

    系列导航 vue学习笔记 一.环境搭建 vue学习笔记 二.环境搭建+项目创建 vue学习笔记 三.文件和目录结构 vue学习笔记 四.定义组件(组件基本结构) vue学习笔记 五.创建子组件实例 v ...

  5. kubernetes scc 故障排查小记

    1. 故障现象 环境在跑自动化测试时打印 error: [ ERROR ] Opening output file '/output.xml' failed: Read-only file syste ...

  6. [转帖]Oracle性能优化-大内存页配置

    一.为什么需要大页面? 如果您有一个大的RAM和SGA,那么HugePages对于Linux上更快的Oracle数据库性能是至关重要的.如果您的组合数据库SGAs很大(比如超过8GB,甚至对于更小的数 ...

  7. [转帖]深入理解mysql-第十章 mysql查询优化-Explain 详解(上)

    目录 一.初识Explain 二.执行计划-table属性 三.执行计划-id属性 四.执行计划-select_type属性 一条查询语句在经过MySQL查询优化器的各种基于成本和规则的优化会后生成一 ...

  8. [转帖]CPU结构对Redis性能的影响

    文章系转载,便于分类和归纳,源文地址:https://wangkai.blog.csdn.net/article/details/111571446 CPU的多核架构和多CPU架构都会影响到Redis ...

  9. [转帖]Linux之系统参数overcommit_memory

    https://www.modb.pro/db/25980 前言:作为DBA,内存的使用情况是重要的监控指标之一,了解内存使用很重要.下面有一个系统参数,对于内存的调用起到重要的作用.大家可以了解一下 ...

  10. Intel 第四代志强可扩展SKU