2017 ICPC BeiJing Regional Hihocoder 1634 Puzzle Game

简略题意:给出一个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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值