热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

P3625[APIO2009]采油区域题解

这道题是一道很好的二位前缀和问题。然而码量有点大。下面规定\(n\)表示行,\(m\)表示列,\(n,m\)同阶。即计算复杂度的时候视\(O(nm)\)为\(O(n^2)\)。首先

这道题是一道很好的二位前缀和问题。

然而码量有点大。

下面规定 \(n\) 表示行,\(m\) 表示列,\(n,m\) 同阶。

即计算复杂度的时候视 \(O(nm)\)\(O(n^2)\)

首先预处理 \(sum_{i,j}\) 表示从 \((1,1)\)\((i,j)\) 的和,也就是二维前缀和,这里略过。

考虑将一个矩阵分成 3 块无非 6 种情况,如下:

在这里插入图片描述

上面 6 种情况又分为 2 类:

第一类是前面两种全横排与全竖排。

对于这一类情况,我们需要 \(O(n^2)\) 枚举两个分割行,然后 \(O(1)\) 求出答案。

因此这里引入两个辅助数组 \(Line_{i,j},Col_{i,j}\)



  • \(Line_{i,j}\) 表示第 \(i\) 行到第 \(j\) 行之间的最大 \(k \times k\) 子矩阵元素和。

  • \(Col_{i,j}\) 表示第 \(i\) 列到第 \(j\) 列之间的最大 \(k \times k\) 子矩阵元素和。

然后考虑如何预处理出这两个数组。

下面以 \(Line_{i,j}\) 为例。

首先,对于形如 \(Line_{i,i+k-1}\) 的结果,由于总共只有 \(k\) 行,此时我们可以枚举这 \(k\) 行里面的子矩阵,至多只有 \(m-k+1\) 个。

这部分复杂度是 \(O(n^2)\)

然后对于任意的 \(Line_{i,j}\),如果 \(j-i+1,说明此时行数非法,空着就好(无贡献),否则采用区间 DP 方式转移:\(Line_{i,j}=\max(Line_{i+1,j},Line_{i,j-1})\)

处理完 \(Line,Col\) 之后,我们就可以 \(O(n^2)\) 枚举,\(O(1)\) 算贡献了。



第二类是后面的四种情况,图我搬过来了:

在这里插入图片描述

细心观察上图可以发现,这一类情况的图中都有一个交点(即图中的红点)。

因此我们考虑 \(O(n^2)\) 枚举这个交点。

但是这样我们依然要 \(O(1)\) 算贡献。

因此我们除了前面的 \(Line,Col\),还要引入一个辅助数组:

\(f_{i,j,0/1/2/3}\) 表示以 \((i,j)\) 为分界点,左上/右上/左下/右下 的最大 \(k \times k\) 子矩阵元素和。包括 \((i,j)\) 这个点。

也就是向下面这张图:

在这里插入图片描述

接下来以预处理 \(f_{i,j,0}\) 为例:

还是看图。

在这里插入图片描述

假设右下角的点为 \((i,j)\),我们要算 \(f_{i,j,0}\)

这个矩形被我分成了 3 类:



  • 绿色的是 \(f_{i,j-1,0}\)

  • 蓝色的是 \(f_{i-1,j,0}\)

  • 黄色的是 \((i-k+1,j-k+1)\)\((i,j)\) 这一块矩形的和。

显然答案只能是上述 3 者的最大值,于是我们可以 \(O(n^2)\) 处理完 \(f_{i,j,0}\)

别的同理。

综上,对于第二类情况,我们就可以 \(O(n^2)\) 枚举交点,\(O(1)\) 计算答案了。



最后的时间复杂度是 \(O(n^2)\)

几个小细节:



  1. 注意在计算 \(f_{i,j,0/1/2/3},Line_{i,j},Col_{i,j}\) 的时候是否合法的判断。

  2. 在转移的时候要注意分割线不能算两次。

比如说下面这样:

在这里插入图片描述

此时的正确答案计算式的其中一种为 \(f_{i,j,0}+f_{i,j+1,1}+Line_{i+1,n}\)

千万注意分界线不能算两次。



  1. 注意 \(n,m\) 不能弄错。

  2. 在计算二维前缀和的时候注意不能出现左上角+右下角与左下角+右上角计算两种情况混着用。

    换句话说,假设当前矩阵左上,右上,左下,右下分别为 \((2,2),(2,4),(4,2),(4,4)\),不能出现传进去 \((4,2),(2,4)\) 并且将其当成矩形左上角与右下角 的错误。

  3. 不能开 long long,否则会 MLE。

    至于答案手算一下就会发现实际上不会炸 int

代码:

/*
========= Plozia =========
Author:Plozia
Problem:P3625 [APIO2009]采油区域
Date:2021/5/14
========= Plozia =========
*/
#include
typedef long long LL;
const int MAXN = 1500 + 10;
int n, m, k, a[MAXN][MAXN], sum[MAXN][MAXN], f[MAXN][MAXN][4], Line[MAXN][MAXN], Col[MAXN][MAXN];
int read()
{
int sum = 0, fh = 1; char ch = getchar();
for (; ch <'0' || ch > '9'; ch = getchar()) fh -= (ch == '-') <<1;
for (; ch >= '0' && ch <= '9'; ch = getchar()) sum = (sum <<3) + (sum <<1) + (ch ^ 48);
return sum * fh;
}
int Max(int fir, int sec) { return (fir > sec) ? fir : sec; }
int Min(int fir, int sec) { return (fir int Get(int r1, int c1, int r2, int c2)
{
if (r1 > r2) std::swap(r1, r2); if (c1 > c2) std::swap(c1, c2);
return sum[r2][c2] - sum[r2][c1 - 1] - sum[r1 - 1][c2] + sum[r1 - 1][c1 - 1];
}
void init()
{
f[k][k][0] = Get(1, 1, k, k);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
{
if (i > k) { f[i][j][0] = Max(f[i][j][0], f[i - 1][j][0]); }
if (j > k) { f[i][j][0] = Max(f[i][j][0], f[i][j - 1][0]); }
if (i - k + 1 > 0 && j - k + 1 > 0) { f[i][j][0] = Max(f[i][j][0], Get(i - k + 1, j - k + 1, i, j)); }
}
f[k][m - k + 1][1] = Get(1, m - k + 1, k, m);
for (int i = 1; i <= n; ++i)
for (int j = m; j >= 1; --j)
{
if (i > k) { f[i][j][1] = Max(f[i][j][1], f[i - 1][j][1]); }
if (j if (i - k + 1 > 0 && j + k - 1 <= m) { f[i][j][1] = Max(f[i][j][1], Get(i - k + 1, j, i, j + k - 1)); }
}
f[n - k + 1][k][2] = Get(n - k + 1, 1, n, k);
for (int i = n; i >= 1; --i)
for (int j = 1; j <= m; ++j)
{
if (i if (j > k) { f[i][j][2] = Max(f[i][j][2], f[i][j - 1][2]); }
if (i + k - 1 <= n && j - k + 1 > 0) { f[i][j][2] = Max(f[i][j][2], Get(i, j - k + 1, i + k - 1, j)); }
}
f[n - k + 1][m - k + 1][3] = Get(n - k + 1, m - k + 1, n, m);
for (int i = n; i >= 1; --i)
for (int j = m; j >= 1; --j)
{
if (i if (j if (i + k - 1 <= n && j + k - 1 <= m) { f[i][j][3] = Max(f[i][j][3], Get(i, j, i + k - 1, j + k - 1)); }
}
}
int main()
{
n = read(), m = read(), k = read();
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
a[i][j] = read();
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j];
init();
for (int i = 1; i + k - 1 <= n; ++i)
{
for (int j = 1; j <= m; ++j)
{
if (j >= k) { Line[i][i + k - 1] = Max(Line[i][i + k - 1], Get(i, j - k + 1, i + k - 1, j)); }
if (j + k - 1 <= m) { Line[i][i + k - 1] = Max(Line[i][i + k - 1], Get(i, j, i + k - 1, j + k - 1)); }
}
}
for (int len = k + 1; len <= n; ++len)
{
for (int i = 1; i <= n; ++i)
{
int j = i + len - 1; if (j > n) break ;
Line[i][j] = Max(Line[i + 1][j], Line[i][j - 1]);
}
}
for (int j = 1; j + k - 1 <= m; ++j)
{
for (int i = 1; i <= n; ++i)
{
if (i >= k) { Col[j][j + k - 1] = Max(Col[j][j + k - 1], Get(i - k + 1, j, i, j + k - 1)); }
if (i + k - 1 <= n) { Col[j][j + k - 1] = Max(Col[j][j + k - 1], Get(i, j, i + k - 1, j + k - 1)); }
}
}
for (int len = k + 1; len <= m; ++len)
{
for (int i = 1; i <= m; ++i)
{
int j = i + len - 1; if (j > m) break ;
Col[i][j] = Max(Col[i + 1][j], Col[i][j - 1]);
}
}
int ans = 0;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
{
ans = Max(ans, Col[1][j - 1] + f[i][j][1] + f[i + 1][j][3]);
ans = Max(ans, Col[j + 1][m] + f[i][j][0] + f[i + 1][j][2]);
ans = Max(ans, f[i][j][0] + f[i][j + 1][1] + Line[i + 1][n]);
ans = Max(ans, f[i][j][2] + f[i][j + 1][3] + Line[1][i - 1]);
}
for (int i = k; i <= n - k + 1; ++i)
for (int j = i + k - 1; j <= n - k + 1; ++j)
ans = Max(ans, Line[1][i] + Line[i + 1][j - 1] + Line[j][n]);
for (int i = k; i <= m - k + 1; ++i)
for (int j = i + k - 1; j <= m - k + 1; ++j)
ans = Max(ans, Col[1][i] + Col[i + 1][j - 1] + Col[j][m]);
printf("%d\n", ans); return 0;
}


推荐阅读
  • 本文介绍了如何使用PHP向系统日历中添加事件的方法,通过使用PHP技术可以实现自动添加事件的功能,从而实现全局通知系统和迅速记录工具的自动化。同时还提到了系统exchange自带的日历具有同步感的特点,以及使用web技术实现自动添加事件的优势。 ... [详细]
  • 使用nodejs爬取b站番剧数据,计算最佳追番推荐
    本文介绍了如何使用nodejs爬取b站番剧数据,并通过计算得出最佳追番推荐。通过调用相关接口获取番剧数据和评分数据,以及使用相应的算法进行计算。该方法可以帮助用户找到适合自己的番剧进行观看。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文详细介绍了云服务器API接口的概念和作用,以及如何使用API接口管理云上资源和开发应用程序。通过创建实例API、调整实例配置API、关闭实例API和退还实例API等功能,可以实现云服务器的创建、配置修改和销毁等操作。对于想要学习云服务器API接口的人来说,本文提供了详细的入门指南和使用方法。如果想进一步了解相关知识或阅读更多相关文章,请关注编程笔记行业资讯频道。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 20211101CleverTap参与度和分析工具功能平台学习/实践
    1.应用场景主要用于学习CleverTap的使用,该平台主要用于客户保留与参与平台.为客户提供价值.这里接触到的原因,是目前公司用到该平台的服务~2.学习操作 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • 本文讨论了在使用Timer控件和键盘触发时可能出现的冲突问题,并提供了解决方法。同时还介绍了如何实现一个类似QQ的小图标只出现在右下角而不在状态栏的程序。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
author-avatar
海家罗
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有