【LOJ】#2068. 「SDOI2016」探险路线

题解

少考虑了情况,导致我以为是暴力讨论一次角落移动
de了两天才反应过来……简直降智

事实上,我们把移动分三类,一种是在边界跳过一段,一种是在左上角上左上左上左这样撞墙,在右下角下右下右下右这么撞墙,另一种是左右左右左右这么撞墙
如果你说还有上下上下这么撞墙,就把整个图旋转180度再做一遍dp就好了

那么就说一种就可以了
我们在角落里的移动,如果想进行左右洄游的话,就不能再次进行角落移动了,除非我们到了右下角

那么我们就通过dp求出我们左右洄游之前进行角落移动到了每一行的左右位置时最大价值
然后进行左右洄游的dp(这个比较简单)
然后把从上面进行完角落移动和左右洄游的dp的数组和下半部分做完角落移动的拼起来(这个下半部分可以通过把图翻转通过同样的dp求出来)

这样的话我就只用说一下角落里乱撞的dp怎么写了!
dp[1/0][i][j]如果是0的话表示这个走到(不一定是撞到)(1,j),之前最远可以达到第i行,1的话是走到(i,1),之前最远可以达到第j列

转移的时候
dp[0][i][j] = max(dp[0][i - 1][j],dp[1][i - 1][j - 1] + cost(i,1)->(1,j))
dp[1][i][j] = max(dp[0][i][j - 1],dp[0][i - 1][j - 1] + cost(1,j)->(i,1))
同时记录一下0数组减去第一行的前j列前缀和 最大值,用来转移跳跃
同理还要记录1数组减去第1列前i行前缀和最大值,也是用来转移跳跃的

这个代码debug得我真是神智不清了
关键是找来LOJ的AC代码对拍居然这个代码还是错的

代码

#include <bits/stdc++.h>
#define enter putchar('
')
#define space putchar(' ')
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define MAXN 1000005
#define mo 999999137
#define pb push_back
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;T f = 1;char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        res = res * 10 + c - '0';
        c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) out(x / 10);
    putchar('0' + x % 10);
}
int N,M;
int val[805][805],a[805][805];
int64 col[805][805],row[805][805];
int64 dp[2][805][805],g[805],R[805],L[805];
int64 fr[805][2],bh[805][2],ans = -1e16;
int64 c1[2][805][805],c2[2][805][805];
int cnt;
void Init() {
    read(N);read(M);
    for(int i = 1 ; i <= N ; ++i) {
        for(int j = 1 ; j <= M ; ++j) {
            read(val[i][j]);
        }
    }
    for(int i = 1 ; i <= N ; ++i) {
        for(int j = 1 ; j <= M ; ++j) {
            row[i][j] = row[i][j - 1] + a[i][j];
            col[i][j] = col[i - 1][j] + a[i][j];
        }
    }

}
void update(int64 &x,int64 y) {
    x = max(x,y);
}
void Calc(int a[805][805],int n,int m) {
    memset(col,0,sizeof(col));
    memset(row,0,sizeof(row));
    for(int i = 1 ; i <= n ; ++i) {
        for(int j = 1 ; j <= m ; ++j) {
            col[i][j] = col[i - 1][j] + a[i][j];
            row[i][j] = row[i][j - 1] + a[i][j];
        }
    }
    for(int i = 0 ; i <= n ; ++i) {
        for(int j = 0 ; j <= m ; ++j) {
            dp[0][i][j] = dp[1][i][j] = -1e16;
        }
    }
    for(int i = 1 ; i <= n ; ++i) {
        for(int j = 1 ; j <= m ; ++j) {
            dp[0][i][j] = row[1][j];
            dp[1][i][j] = col[i][1];
        }
    }
    for(int j = 1 ; j <= m ; ++j) g[j] = dp[1][1][j] - col[1][1];
    for(int i = 2 ; i <= n ; ++i) {
        int64 t0 = dp[0][i][1] - row[1][1];
        for(int j = 2 ; j <= m ; ++j) {
            dp[0][i][j] = max(dp[0][i - 1][j],dp[1][i - 1][j - 1] + row[i][j] + col[i][j] - a[i][j]);
            update(dp[0][i][j],t0 + row[1][j]);
            update(t0,dp[0][i][j] - row[1][j]);
            dp[1][i][j] = max(dp[1][i][j - 1],dp[0][i - 1][j - 1] + row[i][j] + col[i][j] - a[i][j]);
            update(dp[1][i][j],g[j] + col[i][1]);
            update(g[j],dp[1][i][j] - col[i][1]);
        }
    }
    for(int i = 1 ; i <= n ; ++i) {
        L[i] = -1e16;
        for(int j = 1 ; j <= m ; ++j) {
            update(L[i],dp[1][i][j]);
        }
    }
    R[1] = row[1][m];
    for(int j = 1 ; j <= m ; ++j) g[j] = row[1][m] - row[1][j];
    for(int i = 2 ; i <= n ; ++i) {
        R[i] = -1e16;
        for(int j = 1 ; j < m ; ++j) {
            g[j] = max(g[j] + a[i][m],col[i][j + 1] + row[i][m] - row[i][j + 1]);
            update(R[i],dp[0][i][j] + g[j]);
        }
    }
}
void Solve() {
    memcpy(a,val,sizeof(val));
    Calc(a,N,M);
    memset(fr,0,sizeof(fr));memset(bh,0,sizeof(bh));
    for(int i = 1 ; i <= N ; ++i) {
        fr[i][1] = R[i];
        fr[i][0] = L[i];
    }
    for(int i = 1 ; i <= N ; ++i) {
        for(int j = 1 ; j <= M ; ++j) {
            a[i][j] = val[N - i + 1][M - j + 1];
        }
    }

    Calc(a,N,M);
    for(int i = 1 ; i <= N ; ++i) {
        bh[i][0] = R[N - i + 1];
        bh[i][1] = L[N - i + 1];
    }
    memset(row,0,sizeof(row));memset(col,0,sizeof(col));
    for(int i = 1 ; i <= N ; ++i) {
        for(int j = 1 ; j <= M ; ++j) {
            row[i][j] = row[i][j - 1] + val[i][j];
            col[i][j] = col[i - 1][j] + val[i][j];
        }
    }
    int64 l = val[1][1],r = row[1][M];
    int64 t0 = l - col[1][1],t1 = r - col[1][M];
    for(int i = 2 ; i <= N ; ++i) {
        l = t0 + col[i][1];r = t1 + col[i][M];
        update(fr[i][0],r + row[i][M] - val[i][M]);
        update(fr[i][1],l + row[i][M] - val[i][1]);
        update(fr[i][0],l);update(fr[i][1],r);
        t0 = max(t0,fr[i][0] - col[i][1]);
        t1 = max(t1,fr[i][1] - col[i][M]);
    }
    t0 = row[N][M],t1 = val[N][M];
    ans = max(ans,t0 + fr[N - 1][0]);
    for(int i = N - 1 ; i >= 2 ; --i) {
        t0 = max(t0 + val[i][1],bh[i][0]);
        t1 = max(t1 + val[i][M],bh[i][1]);
        ans = max(ans,t0 + fr[i - 1][0]);
        ans = max(ans,t1 + fr[i - 1][1]);
    }
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Init();
    Solve();
    for(int i = 1 ; i <= N ; ++i) {
        for(int j = 1 ; j <= M ; ++j) {
            if(i < j) swap(val[i][j],val[j][i]);
        }
    }
    swap(N,M);
    Solve();
    out(ans);enter;
    return 0;
}
原文地址:https://www.cnblogs.com/ivorysi/p/9533693.html