当前位置: 首页 > news >正文

P7074 [CSP-J 2020] 方格取数

题目传送门

博客传送门

当时打眼一看没看见还能向上走,还在想为什么是个绿题……

进入正题。如果没有向上走的话,就是个经典简单的 dp。所以对于这个问题,我们还是先考虑 dp。

如果说我们按行从上往下转移肯定是有后效性的,不可行。但是我们发现,如果我们向右走,那我们是回不到左边的,这样就没有后效性了。所以我们从左往右转移,也就是从 \(j-1\) 列往第 \(j\) 列转移。

而对于这两列中的任意两个位置 \((k,j-1)\)\((i,j)\),假设我们在 \((k,j-1)\) 这个位置向右走,那么由于不能走重复的格子,肯定是先向右,然后一直向上或向下的,不可能出现折返的情况。

P7074_1_1

P7074_2_1

我们设 \(dp_{i,j}\) 表示考虑到第 \(j\) 列,第 \(i\) 行的最大得分。这样我们就可以枚举上一列里向右走的那个位置了。朴素的转移方程如下:

\[dp_{i,j}=\max\limits_{k=1}^{n}{dp_{k,j-1}+\sum\limits_{l=min(k,j)}^{max(k,j)}{a[i][l]}} \]

这样是 \(O(n^4)\) 的,过不去啊。但是我们可以先求每行竖直方向的前缀和,优化掉累加的一个 \(n\),这样就是 \(O(n^3)\),还是过不去。

我们先把优化后的转移式子写一下:

\[dp_{i,j}=\max\limits_{k=1}^{n}{ \begin{cases} dp_{k,j-1}+sum_{i,j}-sum_{k-1,j} (k \le i)\\ dp_{k,j-1}+sum_{k,j}-sum_{i-1,j} (k > i)\\ \end{cases} } \]

因为我们的枚举顺序肯定是 \(j\) 在外层循环(首先保证是由 \(j-1\) 列转移来),所以枚举 \(i,k\)\(j\) 是固定的,所以我们可以把有关 \(i\)\(k\) 的项分开,也就是:

\[dp_{i,j}=\max\limits_{k=1}^{n}{ \begin{cases} (dp_{k,j-1}-sum_{k-1,j})+(sum_{i,j}) (k \le i)\\ (dp_{k,j-1}+sum_{k,j})-(sum_{i-1,j}) (k > i)\\ \end{cases} } \]

对于 \(k \le i\) 的情况,我们可以正序枚举 \(i\),并时刻记录一个最大值 \(mx\),其中 \(mx=\max\limits_{k=1}^{i}{dp_{k,j-1}-sum_{k-1,j}}\)

这样我们对于一个新加入的可以拿去更新的 \(i\) 直接 \(O(1)\) 更新,然后用 \(mx\) 转移 \(dp_{i,j}\) 即可。\(k > i\) 的情况同理。(不过要倒序枚举)

由于是取最大值,所以我们正着来一遍倒着来一遍,这样对于每个 \((i,j)\),它都被向下来的最优解和向上来的最优解更新过一遍,所以本做法是对的。

代码:

P7074
#include<bits/stdc++.h>
#define int long long
using namespace std;inline int read(){int x=0,f=1;char c=getchar();while(c<48){if(c=='-') f=-1;c=getchar();}while(c>47) x=(x<<1)+(x<<3)+(c^48),c=getchar();return x*f;
}inline void write(int x){if(x<0) putchar('-'),x=-x;if(x<10) putchar(x+'0');else write(x/10),putchar(x%10+'0');
}const int N=1314;
const int inf=1e16;
int n,m,a[N][N],dp[N][N],sum[N][N];
//sum[i][j]:对第j列做前缀和,当前做到第i行 signed main(){n=read(),m=read();for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){a[i][j]=read();sum[i][j]=sum[i-1][j]+a[i][j];}}//由于结果可能为负,所以初始化一定是赋极小值 for(int j=1;j<=n;j++){for(int i=1;i<=m;i++){dp[j][i]=-inf;}}//对于第一列的数来说,显然只能从左上角往下走 for(int j=1;j<=n;j++){dp[j][1]=sum[j][1];}for(int i=2;i<=m;i++){int mx=-inf;//mx:同题解 //计算k<=i时的最优解 for(int j=1;j<=n;j++){//i是当前新加入的可更新mx的位置,更新mx mx=max(mx,dp[j][i-1]-sum[j-1][i]);dp[j][i]=max(dp[j][i],mx+sum[j][i]);}//计算k>i时的最优解 //同上 mx=-inf;for(int j=n;j>=1;j--){mx=max(mx,dp[j][i-1]+sum[j][i]);dp[j][i]=max(dp[j][i],mx-sum[j-1][i]);}}int ans=dp[n][m];printf("%lld",ans);return 0;
}
http://www.jsqmd.com/news/24344/

相关文章:

  • 2025 年中央空调维保服务公司最新推荐榜,技术实力与市场口碑深度解析上海中央空调维保 / 昆山中央空调维修 / 昆山中央空调保养公司推荐
  • 2025年隔热条厂家权威推荐榜单:尼龙隔热条,PA66尼龙隔热条,建筑用隔热条,断桥铝门窗隔热条,门窗隔热条,幕墙隔热条,阳光房隔热条,国标隔热条厂家精选
  • 国产ftp传输文件,提升企业数据安全性的解决方案
  • Unity项目管理员权限问题(Unity is running as administrator )
  • 2025年度线材立式注塑机直销厂家TOP3综合榜单:线材立式注塑机/精密立式注塑机/立式转盘注塑机源头厂家精选。
  • new URLSearchParams 功能用法详解
  • 2025 年防腐木厂家最新推荐榜,技术实力与市场口碑深度解析防腐木凉亭 / 防腐木围栏 / 防腐木木屋 / 防腐木地板公司推荐
  • 一个程序如何连接数据库?以C++为例 - 教程
  • 基于MATLAB的多目标粒子群算法(MOPSO)实现帕累托最优解群
  • 跨网数据交换平台有哪些优势与应用解析
  • 2025 年搬运公司最新推荐榜,技术实力与市场口碑深度解析覆盖工厂搬迁 / 设备搬运 / 吊装搬运全场景公司推荐
  • 2025年度液压式变位机供应商TOP3综合榜单:头尾升降变位机/L型变位机/焊接操作机源头厂家精选
  • 2025年口碑好的合同档案管理系统数字化
  • Spring Boot中Spring Data JPA的常用注解
  • 2025年评价高的澳洲海外仓一件代发跨境电商优选平台榜
  • 向JKS(Java KeyStore)文件中添加证书
  • 2025年评价高的企业目视化规划最新品牌实力榜品牌
  • 2025年口碑好的河南公司注册代理记账企业推荐榜
  • 若干思维题总结
  • 2025年热门的窖藏坛装涪陵榨菜品牌
  • 2025年度印刷机专用稳压器生产商TOP3综合实力榜单:干式稳压器/智能型稳压器/无触点稳压器源头厂家精选。
  • 【译】在 Visual Studio 中引入计划功能(公开预览版)
  • 2025年口碑好的企业VI设计实力公司
  • 2025年评价高的团餐配送最新用户口碑榜品牌
  • 2025 年深圳餐饮设计公司最新推荐榜,聚焦机构专业能力与项目落地成效深度剖析潮流引领 / 功能优化 / 成本精控 / 品牌塑造公司推荐
  • pwn中常用函数
  • 2025 年模压桥架厂家最新推荐榜,技术实力与市场口碑深度解析:高承重耐腐蚀品牌甄选
  • 为什么在componentDidMount()中请求数据?
  • 2025年质量好的云南房屋加固用户好评榜
  • 关心安全与效率?内外网文件交换系统有哪些,一文讲透!