Description
Solution
为方便叙述,令扫地的古明地觉为 A,走路的古明地恋为 B。
首先,考虑当 A 和 B 的路线都固定时,如何找出最优解。
分成两类讨论:
- A 的终点与 B 的终点相同(即
x
s
=
x
k
,
y
s
=
y
k
x_s=x_k,y_s=y_k
xs=xk,ys=yk)。此时两路线的最长公共后缀为一段非空的区间,在图中用黑色表示;剩余部分中,由 A 走的部分为绿色,由 B 走的部分为红色。不难发现,所有仅被绿色经过的点
(
i
,
j
)
(i,j)
(i,j) 的贡献均为
a
i
,
j
a_{i,j}
ai,j,被染为黑色的点的贡献也均为
a
i
,
j
a_{i,j}
ai,j;所有同时被红和绿经过的点
(
i
,
j
)
(i,j)
(i,j) 的贡献均为
max
(
a
i
,
j
,
0
)
\max(a_{i,j},0)
max(ai,j,0),所有仅被红色经过的点
(
i
,
j
)
(i,j)
(i,j) 的贡献也均为
max
(
a
i
,
j
,
0
)
\max(a_{i,j},0)
max(ai,j,0)。无色点贡献显然都是
0
0
0。
- A 的终点与 B 的终点不同。此时两路线的最长不相交后缀为一段非空的区间,在图中用黑色表示;剩余部分中,由 A 走的部分为绿色,由 B 走的部分为红色。不难发现,所有仅被绿色经过的点
(
i
,
j
)
(i,j)
(i,j) 的贡献均为
a
i
,
j
a_{i,j}
ai,j,被染为黑色且由 A 经过点的贡献也均为
a
i
,
j
a_{i,j}
ai,j;所有同时被红和绿经过的点
(
i
,
j
)
(i,j)
(i,j) 的贡献均为
max
(
a
i
,
j
,
0
)
\max(a_{i,j},0)
max(ai,j,0),所有仅被红色经过的点
(
i
,
j
)
(i,j)
(i,j) 的贡献也均为
max
(
a
i
,
j
,
0
)
\max(a_{i,j},0)
max(ai,j,0)。其他点的贡献都是
0
0
0。
于是我们就可以愉快地 dp \text{dp} dp 了。
令 f i , j , k f_{i,j,k} fi,j,k 表示,当 A 和 B 同时从 ( 1 , 1 ) (1,1) (1,1) 出发且 B 走到 ( i , j ) (i,j) (i,j),A 走到 ( k , i + j − k ) (k,i+j-k) (k,i+j−k) 时(所有坐标必须全部合法),所有经过的点的最大贡献和。注意,这里我们不考虑任何黑色路线的贡献,只考虑红绿两部分。
令 g i , j g_{i,j} gi,j 表示,从 ( i , j ) (i,j) (i,j) 出发到达 ( x k , y k ) (x_k,y_k) (xk,yk) 的最大点权和。这是黑色贡献的体现。
g g g 的转移十分容易,那么 f f f 该如何转移呢?首先, f i , j , k f_{i,j,k} fi,j,k 可以由 4 4 4 个不同的前驱得到,分别为 f i , j − 1 , k , f i − 1 , j , k , f i , j − 1 , k − 1 , f i − 1 , j , k − 1 f_{i,j-1,k},f_{i-1,j,k},f_{i,j-1,k-1},f_{i-1,j,k-1} fi,j−1,k,fi−1,j,k,fi,j−1,k−1,fi−1,j,k−1。其次,我们还需要在原来的总贡献上加上当前新扩展出的 ( i , j ) ( k , i + j − k ) (i,j)(k,i+j-k) (i,j)(k,i+j−k) 的贡献——若 i ≠ k i \neq k i=k 则两点不重合,应加上 a i , j + max ( a k , i + j − k , 0 ) a_{i,j}+\max(a_{k,i+j-k},0) ai,j+max(ak,i+j−k,0);否则两点重合,应加上 max ( a i , j , 0 ) \max(a_{i,j},0) max(ai,j,0)。
至于如何计算答案,根据上面的两类讨论很容易得到:
- a n s : = max ( a n s , f i , j − 1 , i − 1 + g i , j ) ans:=\max(ans,f_{i,j-1,i-1}+g_{i,j}) ans:=max(ans,fi,j−1,i−1+gi,j)(第一类)
- a n s : = max ( a n s , f i − 1 , j , i + g i , j ) ans:=\max(ans,f_{i-1,j,i}+g_{i,j}) ans:=max(ans,fi−1,j,i+gi,j)(第一类)
- a n s : = max ( a n s , f i , j , i + g i + 1 , j ) ans:=\max(ans,f_{i,j,i}+g_{i+1,j}) ans:=max(ans,fi,j,i+gi+1,j)(第二类)
- a n s : = max ( a n s , f i , j , i + g i , j + 1 ) ans:=\max(ans,f_{i,j,i}+g_{i,j+1}) ans:=max(ans,fi,j,i+gi,j+1)(第二类)
一定注意还有 a n s : = max ( a n s , g 1 , 1 ) ans:=\max(ans,g_{1,1}) ans:=max(ans,g1,1),这属于第二类情况。
总时间复杂度 O ( n 3 ) O(n^3) O(n3),可以通过本题。
Code
#include <bits/stdc++.h>
#define int long long
#define inf 200000000000000007
using namespace std;
const int maxl=305;
int read(){
int s=0,w=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') w=-w;ch=getchar();}
while (ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+(ch^'0');ch=getchar();}
return s*w;
}
int n,m,sx,sy,tx,ty,ans=-inf;
int a[maxl][maxl],f[maxl][maxl][maxl],g[maxl][maxl];
bool chk(int x,int y,int xx,int yy){return (x<=xx&&y<=yy&&1<=x&&1<=y);}
signed main(){
n=read(),m=read();
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++) a[i][j]=read();
}
for (int i=0;i<=n+1;i++){
for (int j=0;j<=m+1;j++){
g[i][j]=-inf;
for (int k=0;k<=n+1;k++) f[i][j][k]=-inf;
}
}
tx=read(),ty=read(),sx=read(),sy=read();
g[sx][sy]=a[sx][sy];
for (int i=sx;i>=1;i--){
for (int j=sy;j>=1;j--){
if (i) g[i-1][j]=max(g[i-1][j],g[i][j]+a[i-1][j]);
if (j) g[i][j-1]=max(g[i][j-1],g[i][j]+a[i][j-1]);
}
}
f[1][1][1]=max(a[1][1],0ll),ans=g[1][1];
for (int i=1;i<=sx;i++){
for (int j=1;j<=sy;j++){
for (int k=max(1ll,i+j-ty);k<=min(i+j-1,tx);k++){
int w=i+j-k,delta=((i==k)?(max(a[i][j],0ll)):(a[i][j]+max(a[k][w],0ll)));
if (i!=1||j!=1||k!=1) f[i][j][k]=max(max(f[i-1][j][k],f[i-1][j][k-1]),max(f[i][j-1][k],f[i][j-1][k-1]))+delta;
if (chk(i+1,j,sx,sy)&&chk(i,j+1,tx,ty)) ans=max(ans,f[i][j][i]+g[i+1][j]);
if (chk(i,j+1,sx,sy)&&chk(i+1,j,tx,ty)) ans=max(ans,f[i][j][i]+g[i][j+1]);
if (sx==tx&&sy==ty&&chk(i,j,sx,sy)&&chk(i,j,tx,ty)) ans=max(ans,max(f[i-1][j][i],f[i][j-1][i-1])+g[i][j]);
}
}
}
cout<<ans<<endl;
return 0;
}