「EZEC-4.5」走方格

题目链接

Solution

考虑对于每个格子,计算经过它的最长路是多少。从 \((1,1)\) 开始正着 \(\mathrm{dp}\) 一遍,得到数组 \(\mathrm{f1[][]}\),再从 \(\mathrm{(n,m)}\) 开始反着 \(\mathrm{dp}\) 一遍,得到数组 \(\mathrm{f2[][]}\)

对于 \(\mathrm{(i,j)}\),经过它的最长路 \(dis_{i,j}=f1_{i,j}+f2_{i,j}-a_{i,j}\)\(a_{i,j}\) 重复计算)

由于只能向下或向右走,通过观察(口胡),可以发现一个性质:每个与 \((1,1)\)曼哈顿距离只会走 \(1\) 次。换成人话,就是每个左下-右上的对角线将会被经过恰好一次。同一条对角线上的点满足 \(i + j\) 相等。

这样我们考虑维护条对角线上 经过每个点最大价值 的最大值(\(\mathrm{maxx}\))和次大值(\(\mathrm{sec}\))。那么枚举 \(\mathrm{(i,j)}\) 点被置成 \(0\) 之后的最大价值是:

\[\max \left\{ sec_{i+j}, f1_{i,j} + f2_{i,j} - 2 \times a_{i,j} \}\right. \]

\[(如果 \mathrm{dis_{i,j}} 是该对角线的最大值) \]

\[\max \left\{ maxx_{i+j}, f1_{i,j} + f2_{i,j} - 2 \times a_{i,j} \}\right. \]

\[(如果 \mathrm{dis_{i,j}} 不是该对角线的最大值) \]

Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;

const int N = 2333;
LL n, m, Ans = 1e18;
LL idx[N << 4], idy[N << 4], a[N][N], f1[N][N], f2[N][N], maxx[N << 4], sec[N << 4];

signed main()
{
    scanf("%lld%lld", &n, &m);
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            scanf("%lld", &a[i][j]);
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            f1[i][j] = max(f1[i - 1][j] + a[i][j], f1[i][j - 1] + a[i][j]);
    for(int i = n; i >= 1; i--)
        for(int j = m; j >= 1; j--)
            f2[i][j] = max(f2[i + 1][j] + a[i][j], f2[i][j + 1] + a[i][j]);
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
        {
            LL res = f1[i][j] + f2[i][j] - a[i][j];
            if(res > maxx[i + j])
            {
                sec[i + j] = maxx[i + j];
                maxx[i + j] = res;
                idx[i + j] = i, idy[i + j] = j;
            }
            else sec[i + j] = max(sec[i + j], res);
        }
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
        {
            if(idx[i + j] == i && idy[i + j] == j)
                Ans = min(Ans, max(sec[i + j], f1[i][j] + f2[i][j] - 2 * a[i][j]));
            else Ans = min(Ans, max(maxx[i + j], f1[i][j] + f2[i][j] - 2 * a[i][j]));
        }
    printf("%lld", Ans);
    return 0;
}
posted @ 2020-10-05 21:55  Nyxia  阅读(192)  评论(0编辑  收藏  举报