P7160 「dWoi R1」Sixth Monokuma‘s Son-多状态转移动态规划

题目链接「dWoi R1」Sixth Monokuma's Son - 洛谷

题目首先定义矩阵环为,给定一个矩阵 AA,初始全为白色,在其中选定一个子矩阵 A_1A1​ 标黑,再在 A_1A1​ 内选定一个子矩阵 A_2A2​ 标白,就会形成一个矩阵环。注意,矩阵环至少上下左右都有被选定的部分,且整个矩阵环不是一个长方形的矩阵。

假设 + 为黑,- 为白,下面这个就是矩阵环:

---+++++--
---++--+--
---+++++--
---+++++--
----------

下面就不是矩阵环:

------- ------
---+++- --+++-
---+-+- --+++-
------- --+++-

因此,矩阵环会出现上,下,左,右四条边,每个方向有多少个涂黑的部分,就是那个方向的厚度。比如对于第一张符合要求的图,上方,右方的厚度为 11,左方,下方的厚度为 22。

注意,一个完整的矩阵不是一个矩阵环。


接下来是正经的题目背景:

最原得到了“狱原发现一些小昆虫”这个线索后,立刻采取了行动。首先,他利用入间的 遗物,那个类似喷火器的东西,吸进了一些空气,然后,他打算利用机望的机械眼进行查看。

题目描述

机望的机械眼能扫到一片 n \times mn×m 的区域,第 ii 行第 jj 列发现了 a_{i,j}ai,j​ 的不对劲值。

因为机望被外部力量折磨的厉害,所以机望只能锁定一个矩阵环进行查看。机望想求助于你,他想让你锁定一个矩阵环,使得这个矩阵环中的所有位置的不对劲值的和最大,上方,下方的厚度为 11 且上方的那一行在整个区域的第一行,下方的那一行在整个区域的最后一行。至于左右的厚度,机望不限制更多要求。

输入格式

第一行两个整数 n,mn,m 代表整片区域的大小。
接下来 nn 行每行 mm 个整数 a_{i,j}ai,j​ 代表每一个位置的不对劲值。

输出格式

一行一个整数代表答案。
如果不能选出一个符合要求的矩阵环,输出 -1−1。

输入输出样例

输入 #1复制

4 4
3 -4 2 -2
-5 3 -4 2
-1 3 -4 0
3 -3 3 4

输出 #1复制

8

输入 #2复制

1 2
11 45

输出 #2复制

-1

输入 #3复制

7 7
10 10 10 -100 11   11 11
10 10 10 -100 11 -100 11
10 10 10 -100 11 -100 11
10 10 10 -100 11 -100 11
10 10 10 -100 11 -100 11
10 10 10 -100 11 -100 11
10 10 10 -100 11   11 11

输出 #3复制

176

说明/提示

样例说明

关于样例 1 的解释:

可以选择如下形式的矩阵环(但其实两个解是一样的,因为第一列所有数之和为 00):

++++  -+++
++-+  -+-+
++-+  -+-+
++++  -+++

其中 + 为选定的,- 为未选定的。

关于样例 3,提供者 @cmll02,感谢他的贡献。

数据规模与约定

本题采用捆绑测试。

  • Subtask 1(5 pts):n \le 2n≤2 或 m \le 2m≤2。
  • Subtask 2(5 pts):a_{i,j}>0ai,j​>0。
  • Subtask 3(40 pts):m \le 1000m≤1000。
  • Subtask 4(50 pts):无特殊限制。

对于 100\%100% 的数据,1 \le n \le 101≤n≤10,1 \le m \le 10^51≤m≤105,|a_{i,j}| \le 100∣ai,j​∣≤100。

附件下载

D.in333.31KB

D.out7B

---------------------------------------------------------------------------------------------------------------------------------

矩阵环无非是左侧若干列,中间上下若干列,右侧若干列。

每处理到一列,处理出以该列结尾的左侧若干列最大和。

  

   dpleft[i]=max(dpleft[i-1]+s[i],s[i]);

这样我们就获得了左侧部分,可能是继承了前面若干列,也可能是单独开一列。

 然后我们处理出,中间部分,也就是上下两行的那部分。在这里我们把它和左侧合并,形成一个c型

 if(i>=2)
         dpc[i]=max(dpleft[i-1]+sum[i],dpc[i-1]+sum[i]);

sum[i]代表上下两个元素合,dpc[i]可以由新遍历到的i的上下两个元素组成c型,也可以加入前面已经形成的c型。

if(i>=3)
         dpright[i]=max(dpright[i-1]+s[i],dpc[i-1]+s[i]);

 最后再补上右侧的,可以继承原来的,也可以补上前面c型的

# include<iostream>
# include<algorithm>
# include<iomanip>
# include<vector>
# include<map>
# include<math.h>

using namespace std;
typedef long long int ll;

ll s[100000+10],sum[100000+10],a[15][100000+10], dpleft[100000+10],dpc[100000+10],dpright[100000+10];
ll mininf=-9999999999;
int main()
{

     int n,m;
     cin>>n>>m;
     
     if(n<=2||m<=2)
     {
         cout<<-1;
         return  0;
     }
     fill(dpleft,dpleft+100000+10,mininf);
     fill(dpc,dpc+100000+10,mininf);
     fill(dpright,dpright+100000+10,mininf);


     for(int i=1;i<=n;i++)
     {
         for(int j=1;j<=m;j++)
         {
             cin>>a[i][j];

             s[j]+=a[i][j];
               if(i==1||i==n)
            sum[j]+=a[i][j];

         }

     }

     ll ans=mininf;


     for(int i=1;i<=m;i++)
     {
         dpleft[i]=max(dpleft[i-1]+s[i],s[i]);
         if(i>=2)
         dpc[i]=max(dpleft[i-1]+sum[i],dpc[i-1]+sum[i]);
         if(i>=3)
         dpright[i]=max(dpright[i-1]+s[i],dpc[i-1]+s[i]);

         ans=max(dpright[i],ans);
     }

     if(ans>mininf)
     cout<<ans;
     else
        cout<<-1;
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qinsanma and Code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值