简略题意:给出一个n*m的矩阵,可以修改其中一个数字为p,使得最大子矩阵的值最小化。
暴力的做法就是n*m的枚举节点,然后每次
n3
的求最大子矩阵。
其实没有必要,假若我们求出了最大子矩阵唯一,那么我们只要枚举最大子矩阵的一个值修改之后,再求即可。
假若最大子矩阵不唯一,那么我们还是只要枚举任意一个最大子矩阵的值即可。因为如果两个最大子矩阵的有公共部分,那么答案必然可以被枚举到。如果没有公共部分,那么怎么修改都不会改变答案。
因此我只需要枚举任意一个最大子矩阵的所有点进行修改,想办法加速新图上最大子矩阵的求解即可。
对此我们只需要预处理出每个点上/下/左/右的最大子矩阵分别是多少。
令原来图的最大子矩阵的值为ans,那么新图的最大子矩阵即为max(ans - v[i][j] + p, L, R, U, D)。
复杂度
O(n3)
。
#define others
#ifdef poj
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
#endif // poj
#ifdef others
#include <bits/stdc++.h>
#endif // others
//#define file
#define all(x) x.begin(), x.end()
using namespace std;
const double eps = 1e-8;
int dcmp(double x) { if(fabs(x)<=eps) return 0; return (x>0)?1:-1;};
typedef long long LL;
typedef unsigned long long ULL;
void file() {
freopen("out.txt", "r", stdin);
freopen("out1.txt", "w", stdout);
}
namespace Solver {
int n, m, p;
const int maxn = 160;
int L[maxn], R[maxn], U[maxn], D[maxn];
int v[maxn][maxn];
int S[maxn][maxn];
void solve() {
while(~scanf("%d%d%d", &n, &m, &p)) {
memset(L, -0x3f3f3f3f, sizeof L);
memset(R, -0x3f3f3f3f, sizeof R);
memset(U, -0x3f3f3f3f, sizeof U);
memset(D, -0x3f3f3f3f, sizeof D);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
scanf("%d", &v[i][j]), S[i][j] = S[i-1][j] + S[i][j-1] - S[i-1][j-1] + v[i][j];
int st, et;
int sx, sy, ex, ey;
int maxans = -0x3f3f3f3f;
for(int i = n; i >= 1; i--)
for(int j = i; j <= n; j++) {
int x = 0;
int ans = -0x3f3f3f3f;
for(int k = 1; k <= m; k++) {
int val = S[j][k] - S[i-1][k] - (S[j][k-1] - S[i-1][k-1]);
if(x < 0) x = val;
else x += val;
ans = max(ans, x);
}
D[i-1] = max(D[i-1], max(D[i], ans));
maxans = max(maxans, ans);
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= i; j++) {
int x = 0;
int ans = -0x3f3f3f3f;
for(int k = 1; k <= m; k++) {
int val = S[i][k] - S[j-1][k] - (S[i][k-1] - S[j-1][k-1]);
if(x < 0) x = val;
else x += val;
ans = max(ans, x);
}
U[i+1] = max(U[i+1], max(U[i], ans));
}
for(int i = 1; i <= m; i++)
for(int j = 1; j <= i; j++) {
int x = 0;
int ans = -0x3f3f3f3f;
for(int k = 1; k <= n; k++) {
int val = S[k][i] - S[k][j-1] - (S[k-1][i] - S[k-1][j-1]);
if(x < 0) x = val;
else x += val;
ans = max(ans, x);
}
L[i+1] = max(L[i+1], max(L[i], ans));
}
for(int i = m; i >= 1; i--)
for(int j = i; j <= m; j++) {
int x = 0;
int ans = -0x3f3f3f3f;
for(int k = 1; k <= n; k++) {
int val = S[k][j] - S[k][i-1] - (S[k-1][j] - S[k-1][i-1]);
if(x < 0) x = val;
else x += val;
ans = max(ans, x);
}
R[i-1] = max(R[i-1], max(R[i], ans));
}
for(int i = 1; i <= n; i++)
for(int j = i; j <= n; j++) {
int x = 0;
int ans = -0x3f3f3f3f;
st = 1;
for(int k = 1; k <= m; k++) {
int val = S[j][k] - S[i-1][k] - (S[j][k-1] - S[i-1][k-1]);
if(x < 0) st = k, x = val;
else x += val;
if(x == maxans) {
et = k;
sx = i, sy = st, ex = j, ey = et;
goto LOOP;
}
}
}
LOOP: ;
int fans = maxans;
for(int i = sx; i <= ex; i++)
for(int j = sy; j <= ey; j++) {
fans = min(fans, max(maxans - v[i][j] + p, max(L[j], max(R[j], max(U[i], D[i])))));
}
cout<<fans<<endl;
}
}
}
int main() {
// file();
Solver::solve();
return 0;
}