题意:给一个n*m的矩阵,你只能选择一个格子把这个格子的数换成p(也可以一个都不换),问最大子矩阵和最小可能是多少?

思路:

思路就是上面这个思路,这里简单讲一下怎么n^3求最大子矩阵和:枚举两行(或者两列),然后把每一列之和看做一个数字,这样二维就变成了一维,我们可以直接求最大子串和的方法。初始一个ret为0,然后从左往右加,如果ret<0,那么把ret初始化0,负数作为初始值肯定比重新开始小,然后找出ret的最大值就是最大子矩阵和。

代码:

#include<cstdio>
#include<cstring>
typedef long long ll;
using namespace std;
const int maxn = + ;
const int MOD = 1e9 + ;
const int INF = 0x3f3f3f3f;
int num[maxn][maxn], sum[maxn][maxn];
int up[maxn], down[maxn], left[maxn], right[maxn];
int n, m, p, xx1, yy1, xx2, yy2;
int min(int x, int y){
return x < y? x : y;
}
int max(int x, int y){
return x > y? x : y;
}
int mat(int x1, int y1, int x2, int y2){
return sum[x2][y2] - sum[x1 - ][y2] - sum[x2][y1 - ] + sum[x1 - ][y1 - ];
}
int main(){
while(~scanf("%d%d%d", &n, &m, &p)){
memset(sum, , sizeof(sum));
for(int i = ; i <= n; i++){
for(int j = ; j <= m; j++){
scanf("%d", &num[i][j]);
sum[i][j] = num[i][j] + sum[i - ][j] + sum[i][j - ] - sum[i - ][j - ];
}
} //上下左右四个矩阵预处理
memset(up, -INF ,sizeof(up));
for(int i = ; i <= n; i++){
int tmp = -INF;
for(int j = ; j <= i; j++){
int ret = ;
for(int k = ; k <= m; k++){
ret += mat(j, k, i, k);
tmp = max(tmp, ret);
if(ret < ) ret = ;
}
}
up[i] = max(up[i - ], tmp);
}
memset(down, -INF, sizeof(down));
for(int i = n; i >= ; i--){
int tmp = -INF;
for(int j = i; j <= n; j++){
int ret = ;
for(int k = ; k <= m; k++){
ret += mat(i, k, j, k);
tmp = max(tmp, ret);
if(ret < ) ret = ;
}
}
down[i] = max(down[i + ], tmp);
}
memset(left, -INF, sizeof(left));
for(int i = ; i <= m; i++){
int tmp = -INF;
for(int j = ; j <= i; j++){
int ret = ;
for(int k = ; k <= n; k++){
ret += mat(k, j, k, i);
tmp = max(ret, tmp);
if(ret < ) ret = ;
}
}
left[i] = max(left[i - ], tmp);
}
memset(right, -INF, sizeof(right));
for(int i = m; i >= ; i--){
int tmp = -INF;
for(int j = i; j <= m; j++){
int ret = ;
for(int k = ; k <= n; k++){
ret += mat(k, i, k, j);
tmp = max(ret, tmp);
if(ret < ) ret = ;
}
}
right[i] = max(right[i + ], tmp);
} int Max = -INF;
for(int i = ; i <= n; i++){
for(int j = ; j <= i; j++){
int ret = , start = ;;
for(int k = ; k <= m; k++){
ret += mat(j, k, i, k);
if(ret > Max){
Max = ret;
xx1 = j, yy1 = start, xx2 = i, yy2 = k;
}
if(ret < ) ret = , start = k + ;
}
}
}
int ans = Max;
for(int i = xx1; i <= xx2; i++){
for(int j = yy1; j <= yy2; j++){
if(p > num[i][j]) continue;
ans = min(ans , max(Max - num[i][j] + p, max(up[i - ], max(down[i + ], max(left[j - ], right[j + ])))));
}
}
printf("%d\n", ans);
}
return ;
}

HihoCoder 1634 Puzzle Game(最大子矩阵和)题解的更多相关文章

  1. Hihocoder 1634 Puzzle Game(2017 ACM-ICPC 北京区域赛 H题,枚举 + 最大子矩阵变形)

    题目链接  2017 Beijing Problem H 题意  给定一个$n * m$的矩阵,现在可以把矩阵中的任意一个数换成$p$,求替换之后最大子矩阵的最小值. 首先想一想暴力的方法,枚举矩阵中 ...

  2. Puzzle Game HihoCoder - 1634

    题目链接:https://cn.vjudge.net/problem/HihoCoder-1634 题目意思:可以让矩阵里的某一个数变成p,或者不修改.求最大子矩阵最小,输出最小值. 思路:请看下图 ...

  3. ZOJ 1602 Multiplication Puzzle(区间DP)题解

    题意:n个数字的串,每取出一个数字的代价为该数字和左右的乘积(1.n不能取),问最小代价 思路:dp[i][j]表示把i~j取到只剩 i.j 的最小代价. 代码: #include<set> ...

  4. hihocoder #1301 : 筑地市场 数位dp+二分

    题目链接: http://hihocoder.com/problemset/problem/1301?sid=804672 题解: 二分答案,每次判断用数位dp做. #include<iostr ...

  5. hihocoder #1224 : 赛车 dfs

    #1224 : 赛车 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://hihocoder.com/problemset/problem/1224 ...

  6. 牛客网暑期ACM多校训练营(第二场)carpet

    传送门:carpet 题意 有一个n*m的地毯,aij表示地毯每格的元素,bij表示地毯每格的价格,要求选取一块价格最大值最小的地毯,并且这块地毯无限铺开之后,原地毯是其子矩阵. 题解 先找到这个矩阵 ...

  7. NOI题库 1768最大子矩阵 题解

    NOI题库 1768最大子矩阵  题解     总时间限制: 1000ms 内存限制: 65536kB   描述   已知矩阵的大小定义为矩阵中所有元素的和.给定一个矩阵,你的任务是找到最大的非空(大 ...

  8. 【题解】Puzzle [Uva1399]

    [题解]Puzzle [Uva1399] 传送门:\(\text{Puzzle [Uva1399]}\) [题目描述] 给定 \(m\) 和 \(n\),表示有 \(m\) 种不同的字符(大写字母\( ...

  9. hihoCoder [Offer收割]编程练习赛3 D子矩阵求和

    子矩阵求和 http://hihocoder.com/discuss/question/3005 声明一下: n是和x一起的,m是和y一起的 x是横着的,y是纵着的,x往右为正,y往下为正 (非常反常 ...

随机推荐

  1. base64的编码

    计算机中的数据一般是由ascii编码,来存储的, 0---31以及127,表示的是控制字符: 32-126表示的是字符,包括空格,阿拉伯数字,大小写字母: 之后的128个字符,是不可见的字符, 在网络 ...

  2. Python全栈-day4-语法基础2

    一.字符串 1.字符串基础 1)作用:用于描述姓名.性别.地址等信息 2)定义方式:单引号或者双引号以及三引号内添加字符 注:day3中介绍 name = 'zhang' user_name = &q ...

  3. lua学习之循环打印九九乘法表

    --第4题 输出99乘法表 function PrintMulitiplyTable() , do local res = {} local str = "" , i do res ...

  4. Rower Bo (高数 + 物理)

    #include<bits/stdc++.h> #define esp (1e-5) using namespace std; int main(){ int a; double v1, ...

  5. 使用IntelljIDEA生成接口的类继承图及装饰器模式

    类图生成方法 以一个装饰器模式实现数学运算的例子为例. 安装 Intellj Ultimate , lience server: http://xdouble.cn:8888/ 在类上右键点击 cla ...

  6. 【转】Tomcat 快速入门

    本文转载自:https://www.cnblogs.com/jingmoxukong/p/8258837.html?utm_source=gold_browser_extension 目录 Tomca ...

  7. linux常用命令:cd 命令

    Linux cd 命令可以说是Linux中最基本的命令语句,其他的命令语句要进行操作,都是建立在使用 cd 命令上的.所以,学习Linux 常用命令,首先就要学好 cd 命令的使用方法技巧. 1. 命 ...

  8. XWIKI部署安装

    http://www.linuxidc.com/Linux/2016-08/134408.htm

  9. linux 查找locate find

    1.locate locate指令和find找寻档案的功能类似,但locate是透过update程序将硬盘中的所有档案和目录资料先建立一个索引数据库,在 执行loacte时直接找该索引,查询速度会较快 ...

  10. Android屏幕适配全攻略(最权威的官方适配指导)

    摘自:http://www.cocoachina.com/android/20151030/13971.html Android屏幕适配出现的原因 在我们学习如何进行屏幕适配之前,我们需要先了解下为什 ...